继承虚函数浅谈 c++ 类,继承类,有虚函数的类,虚拟继承的类的内存布局,使用vs2010打印布局结果。
本文笔者在青岛逛街的时候突然想到的...最近就有想写几篇关于继承虚函数的笔记,所以回家到之后就奋笔疾书的写出来发布了
应用sizeof函数求类巨细这个问题在很多面试,口试题中很轻易考,而涉及到类的时候,又不得不说类的继承,虚继承,虚函数,所以涉及到了类的内存布局,其中关于虚拟继承(virtual public)这个话题比拟难以懂得,而且不同的编译器环境可能实现的类的内存布局不同,所以本文仅在ms vs2010编译环境下调试,如果你在像cfree这样的编译器中调试结果会不同当涉及到虚拟继承的时候。好了,我们一起来学习吧:
首先关于空类的巨细:
class A
{ };
sizeof(A)==1;
为什么不是0?因为类的实例化,即使是空类,编译器也会默认给类添加一个字节,使其有无独有偶的地址。
关于 static 成员,结构,析构,一般成员函数,应用sizeof求类巨细的时候,这些是不考虑在内的,因为static成员是所有类对象所同享的,它不是某一个对象的成员,而是具有类的属性,一般成员函数包括结构和析构函数:所以类对象调用时都是同一个函数地址,所以不计算在内。
关于虚函数:
class A{
int a;
virtual ~A();
};
sizeof(A)==8;
虚函数大家都晓得,一般类实例的最靠前的地址是vfptr(虚函数表指针),这个指针指向这个类的虚函数表(函数指针数组),这个表里放着类的所有虚函数。关于虚函数更多的机理大家可以谷歌之。
所以这里多了一个vfptr指针,共8字节。
关于内存补齐:
class A{
char a;
virtual void f();
};
sizeof(A)==8;
a本来是1个字节,但是这里会有一个<alignment member>(size =3)补齐了3个字节,所以一共8个字节。
下面关于虚拟继承:
class A
{
public:
virtual void aa(){};
char a;
};
class B:virtual public A
{
public:
virtual void bb(){};
char b;
};
class C:virtual public A
{
public:
virtual void cc(){};
char c;
};
class D:public B,public C
{
public:
virtual void dd(){};
char d;
};
sizeof(A)==8;
sizeof(B)==20;
sizeof(C)==20;
sizeof(D)==36;
有点难以懂得吧,没关系,我利用vs2010的命令行操纵: cl /d1 reportSingleClassLayout类名 程序名.cpp
打印了4个类的内存布局,我们一起来看看:
我们可以看出A的巨细为8字节:
vfptr---->(virtual function table pointer)虚函数表指针,4个字节。
a----->成员变量4字节,其中补齐了3个字节。
最后部分为A的虚函数表,我们可以看出A只有一个虚函数:A::aa。
下面看B的内存布局:
谁说人与人隔着遥远的重洋,谁说心与心设着坚固的堤防?十六岁的鸟儿飞上天空,总会找到落脚的枝头。
B的巨细为20:我们须要注意的是B是从A虚拟继承而来的,所以:
vfptr------>自己新增的虚函数表指针4字节;vbprt-------->虚基类表指针,指向B的虚基类4字节;成员变量b,4字节(补齐3个字节);
包含虚基类A的:vfptr------>A的虚函数表指针;成员a(同样补齐3个字节)。
C的内存布局和B一样,下面看D的内存布局:
因为D是从B和C共有继承而来,不是虚继承,所以D没有新增自己的虚函数表指针和虚基类表指针,仅仅包括:
基类B的vfptr,vbptr,b,然后基类C的vfptr,vbptr,c,成员变量d,基类A的vfptr,成员变量a;总共36字节。
我们再看下面一种情况:
class A
{
public:
virtual void aa(){};
char a;
};
class B:virtual public A
{
public:
virtual void bb(){};
char b;
};
class C:virtual public A
{
public:
virtual void cc(){};
char c;
};
class D:virtual public B,virtual public C
{
public:
virtual void dd(){};
char d;
};
sizeof(A)==8;
sizeof(B)==20;
sizeof(C)==20;
sizeof(D)==44;
与上面情况唯一不同的是D,因为它同时从B和C虚继承失掉,下面我们看D的内存布局:
这已经很一览无余了吧:由于是虚拟继承,所以在最开始多了自己的一个vfptr和vbptr,其他的没有改变。
下面我们来看最后一种情况:
class A
{
public:
virtual void aa(){};
char a;
};
class B: {
public:
virtual void bb(){};
char b;
};
class C:virtual public A, virtual public B
{
public:
virtual void cc(){};
char c;
};
我相信你已经能得出三个类的巨细了吧,没错:sizeof(A)==8,sizeof(B)=8,sizeof(C)==28;
还须要我解释吗?看内存布局图吧:
没错,这已经一览无余了。
下面总结下:如果类中有虚函数,则会多一个一个虚函数表指针vfptr,如果是虚继承,则子类会新增一个自己的虚函数表指针,然后还会有一个
指向虚基类表的指针vbptr。这就是c++中类继承中的内存布局情况,若有错误,恳请教正。
文章结束给大家分享下程序员的一些笑话语录:
一个合格的程序员是不会写出 诸如 “摧毁地球” 这样的程序的,他们会写一个函数叫 “摧毁行星”而把地球当一个参数传进去。
---------------------------------
原创文章 By
继承和虚函数
---------------------------------
继承虚函数浅谈 c++ 类,继承类,有虚函数的类,虚拟继承的类的内存布局,使用vs2010打印布局结果。的更多相关文章
- 从Java继承类的重名static函数浅谈解析调用与分派
在java中,static成员函数是否可以被重写呢? 结论是,你可以在子类中重写一个static函数,但是这个函数并不能像正常的非static函数那样运行. 也就是说,虽然你可以定义一个重写函数,但是 ...
- 《转》 浅谈C# 多态的魅力(虚方法,抽象,接口实现)
前言:我们都知道面向对象的三大特性:封装,继承,多态.封装和继承对于初学者而言比较好理解,但要理解多态,尤其是深入理解,初学者往往存在有很多困惑,为什么这样就可以?有时候感觉很不可思议,由此,面向对象 ...
- 浅谈C# 多态的魅力(虚方法,抽象,接口实现)
前言:我们都知道面向对象的三大特性:封装,继承,多态.封装和继承对于初学者而言比较好理解,但要理解多态,尤其是深入理解,初学者往往存在有很多困惑,为什么这样就可以?有时候感觉很不可思议,由此,面向对象 ...
- 浅谈Excel开发:四 Excel 自定义函数
我们知道,Excel中有很多内置的函数,比如求和,求平均,字符串操作函数,金融函数等等.在有些时候,结合业务要求,这些函数可能不能满足我们的需求,比如我想要一个函数能够从WebService上获取某只 ...
- Javascript-回调函数浅谈
回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数.回调函数不是由该函数的实现方直接调用,而是在特定 ...
- 浅谈Excel开发:五 Excel RTD函数
上文介绍了Excel中的UDF函数,本文介绍一下同样重要的RTD函数.从Excel 2002开始,Excel引入了一种新的查看和更新实时数据的机制,即real-time data简称RTD函数 ...
- Sql Server存储过程和函数浅谈
今天给大家总结一下sql server中的存储过程和函数.本人是小白,里面内容比较初级,大神不喜勿喷 自行飘过就是.. 首先给大家简单列出sql server中的流控制语句,后面会用到的^_^ sql ...
- Hash函数浅谈
Hash函数是指把一个大范围映射到一个小范围.把大范围映射到一个小范围的目的往往是为了节省空间,使得数据容易保存. 除此以外,Hash函数往往应用于查找上.所以,在考虑使用Hash函数之前,需要明白它 ...
- 从SG函数浅谈解决博弈问题的通法
基于笔者之前对于几种二元零和博弈游戏的介绍,这里将其思想进行简单的提炼,并引出解决这类二元零和博弈游戏的强大工具——SG函数. 其实对于博弈游戏如Bash.Nim等基本类型,异或一些比较高级的棋类游戏 ...
随机推荐
- VS2008+ffmpeg SDK3.2调试tutorial01
最近研究ffmpeg,在ubuntu下感觉不太好调试,老是找不到函数的声明.所以我就把他移到windows下用vs2008分析 关于环境的搭建,我参考了 http://hi.baidu.com/for ...
- 【转】cocos2d-x 3.2 Fast TileMap
概述 在游戏中常常会有丰富的背景元素,如果直接使用大的背景图实现,这会造成资源浪费.TileMap就是为了解决这问题而产生的.Cocos2d-x支持使用Tile地图编辑器创建的TMX格式的地图. Co ...
- JavaScript的事件代理(转)
如果你想给网页添加点JavaScript的交互性,也许你已经听过JavaScript的事件代理(event delegation),并且觉得这是那些发烧友级别的JavaScript程序员才会关心的什么 ...
- MySQL压测中遇到的一些问题
批量insert http://blog.csdn.net/xiaoxian8023/article/details/20155429 Mysql jdbc 批处理数据,需要给jdbc连接加上rewr ...
- Android应用程序版本号管理(官方文档中文版)
在应用程序的 升级/维护 策略中, 版本是一个关键的组成部分. 用户需要了解在他们的设备上所安装的应用程序的版本的特定信息, 以及已安装程序的升级版本可用的情况. 其他应用程序 - 作为同一个套件中发 ...
- Easy steps to create a System Tray Application with C# z
Hiding the C# application to the system tray is quiet straight forward. With a few line of codes in ...
- A标记点击后去掉虚线
没加时,谷歌无虚线,但ie有虚线. 加上这句,所有的a标签点击都没有虚线了. a {outline: none;} a:active {star:expression_r(this.onFocus=t ...
- Islands and Bridges(POJ 2288状压dp)
题意:给你一个图和每个点的价值,边权值为连接两点权值的积,走哈密顿通路,若到达的点和上上个点相连则价值加三点乘积,求哈密顿通路的最大价值,和最大价值哈密顿通路的条数. 分析:开始看这个题很吓人,但想想 ...
- 试验Windows Embedded Standard 7 Service Pack 1 Evaluation Edition
=========================================== 是否支持再使用 RT 7 Lite 精简 ? ================================= ...
- asp.net中遍历界面上所有控件进行属性设置
* 使用方法: * 前台页面调用方法,重置: protected void Reset_Click(object sender, EventArgs e) { ...