继承虚函数浅谈 c++ 类,继承类,有虚函数的类,虚拟继承的类的内存布局,使用vs2010打印布局结果。
2013-06-22 22:18
393 查看
本文笔者在青岛逛街的时候突然想到的...最近就有想写几篇关于继承虚函数的笔记,所以回家到之后就奋笔疾书的写出来发布了
应用sizeof函数求类巨细这个问题在很多面试,口试题中很轻易考,而涉及到类的时候,又不得不说类的继承,虚继承,虚函数,所以涉及到了类的内存布局,其中关于虚拟继承(virtual public)这个话题比拟难以懂得,而且不同的编译器环境可能实现的类的内存布局不同,所以本文仅在ms vs2010编译环境下调试,如果你在像cfree这样的编译器中调试结果会不同当涉及到虚拟继承的时候。好了,我们一起来学习吧:
首先关于空类的巨细:
为什么不是0?因为类的实例化,即使是空类,编译器也会默认给类添加一个字节,使其有无独有偶的地址。
关于 static 成员,结构,析构,一般成员函数,应用sizeof求类巨细的时候,这些是不考虑在内的,因为static成员是所有类对象所同享的,它不是某一个对象的成员,而是具有类的属性,一般成员函数包括结构和析构函数:所以类对象调用时都是同一个函数地址,所以不计算在内。
关于虚函数:
虚函数大家都晓得,一般类实例的最靠前的地址是vfptr(虚函数表指针),这个指针指向这个类的虚函数表(函数指针数组),这个表里放着类的所有虚函数。关于虚函数更多的机理大家可以谷歌之。
所以这里多了一个vfptr指针,共8字节。
关于内存补齐:
a本来是1个字节,但是这里会有一个<alignment member>(size =3)补齐了3个字节,所以一共8个字节。
下面关于虚拟继承:
有点难以懂得吧,没关系,我利用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字节。
我们再看下面一种情况:
与上面情况唯一不同的是D,因为它同时从B和C虚继承失掉,下面我们看D的内存布局:
这已经很一览无余了吧:由于是虚拟继承,所以在最开始多了自己的一个vfptr和vbptr,其他的没有改变。
下面我们来看最后一种情况:
我相信你已经能得出三个类的巨细了吧,没错:sizeof(A)==8,sizeof(B)=8,sizeof(C)==28;
还须要我解释吗?看内存布局图吧:
没错,这已经一览无余了。
下面总结下:如果类中有虚函数,则会多一个一个虚函数表指针vfptr,如果是虚继承,则子类会新增一个自己的虚函数表指针,然后还会有一个
指向虚基类表的指针vbptr。这就是c++中类继承中的内存布局情况,若有错误,恳请教正。
文章结束给大家分享下程序员的一些笑话语录:
一个合格的程序员是不会写出 诸如 “摧毁地球” 这样的程序的,他们会写一个函数叫 “摧毁行星”而把地球当一个参数传进去。
---------------------------------
原创文章 By
继承和虚函数
---------------------------------
应用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打印布局结果。
- C++中包含有虚函数的单继承状态下的类的内存布局
- C++中包含有虚函数的单继承状态下的类的内存布局
- Visual C++ 8.0对象布局的奥秘:虚函数、多继承、虚拟继承(VC直接输出内存布局)
- C++对象内存布局--③测试多继承中派生类的虚函数在哪一张虚函数表中
- 浅谈C++多态性 & C++虚继承的实现方式与内存布局
- C++继承 派生类中的内存布局(单继承、多继承、虚拟继承)
- 三十二、C++内存布局,对象大小计算、虚函数虚继承对类内存模型的影响
- C++ 对象的内存布局—— 虚继承下的虚函数
- C++使用继承时子对象的内存布局
- C++程序运行时内存布局之----------无继承情况下的虚函数
- C++程序运行时内存布局之----------无继承情况下的虚函数
- Linux Debugging(四): 使用GDB来理解C++ 对象的内存布局(多重继承,虚继承)
- Linux Debugging(四): 使用GDB来理解C++ 对象的内存布局(多重继承,虚继承)
- c++继承中的内存布局
- C++ 类继承内存布局
- C++中虚函数工作原理和(虚)继承类的内存占用大小计算
- C++ 多重继承和虚继承的内存布局
- C++对象内存布局--虚基类表的使用
- C++ 多继承和虚继承的内存布局