最近看了下Inside C++里面讲的对虚继承层次的对象的内存布局,发如今不一样编译器实现有所区别。所以,本身动手探索了一下。结果以下:
首先,说说GCC的编译器.
它实现比较简单,无论是否虚继承,GCC都是将虚表指针在整个继承关系中共享的,不共享的是指向虚基类的指针。
class A {
int a;
virtual ~A(){}
};
class B:virtual public A{
virtual ~B(){}
virtual void myfunB(){}
};
class C:virtual public A{
virtual ~C(){}
virtual void myfunC(){}
};
class D:public B,public C{
virtual ~D(){}
virtual void myfunD(){}
};
以上代码中 sizeof(A)=8,sizeof(B)=12,sizeof(C)=12,sizeof(D)=16.
解释:A中int+虚表指针。B,C中因为是虚继承所以大小为A+指向虚基类的指针,B,C虽然加入了本身的虚函数,可是虚表指针是和基类共享的,所以不会有本身的虚表指针。D因为B,C都是虚继承,所以D只包含一个A的副本,因而D大小就等于A+B中的指向虚基类的指针+C中的指向虚基类的指针。
若是B,C不是虚继承,而是普通继承的话,那么A,B,C的大小都是8(没有指向虚基类的指针了),而D因为不是虚继承,所以包含两个A副本,大小为16. 注意此时虽然D的大小和虚继承同样,可是内存布局却不一样。
而后,来看看VC的编译器
vc对虚表指针的处理比GCC复杂,它根据是否为虚继承来判断是否在继承关系中共享虚表指针,而对指向虚基类的指针和GCC同样是不共享,固然也不可能共享。
代码同上。
运行结果将会是sizeof(A)=8,sizeof(B)=16,sizeof(C)=16,sizeof(D)=24.
解释:A中依然是int+虚表指针。B,C中因为是虚继承所以虚表指针不共享,因为B,C加入了本身的虚函数,因此B,C分别本身维护一个虚表指针,它指向本身的虚函数。(注意:只有子类有新的虚函数时,编译器才会在子类中添加虚表指针)所以B,C大小为A+本身的虚表指针+指向虚基类的指针。D因为B,C都是虚继承,所以D只包含一个A的副本,同时D是从B,C普通继承的,而不是虚继承的,所以没有本身的虚表指针。因而D大小就等于A+B的虚表指针+C的虚表指针+B中的指向虚基类的指针+C中的指向虚基类的指针。
一样,若是去掉虚继承,结果将和GCC结果同样,A,B,C都是8,D为16,缘由就是VC的编译器对于非虚继承,父类和子类是共享虚表指针的。ide