参考文献:《深度探索C++对象模型》
https://bbs.csdn.net/topics/390083150
https://blog.csdn.net/u011841639/article/details/39156347
运行平台:Visual Studio 2015(32bits)
我在上一篇博客(https://blog.csdn.net/m0_38014304/article/details/84286266)(看了这一篇就不用看上一篇了)中探讨了C++中虚继承对类的sizeof大小的影响,而当虚继承与多重继承、多态联系在一起时,其sizeof的结果使得我又产生了困惑。这次我关于类中编译器附加的“虚函数表指针”和“虚基类指针”进行了相关研究,主要针对存在多态的虚继承的对象模型,在此特别感谢大佬(https://blog.csdn.net/u011841639/article/details/39156347)所给的启发,我们开始吧。
源码:
# include <iostream>
using namespace std;
class X
{
public:
virtual ~X() {}
protected:
int m_x;
};
class Y :virtual public X
{
public:
// virtual void test_y() {}
protected:
//int m_y;
};
class Z :virtual public X
{
public:
virtual void test_z() {}
//int m_z;
};
class A:public Y, public Z
{
public:
virtual void test_a() {}
};
class B
{
public:
virtual ~B() {}
};
class C
{
public:
virtual ~C() {}
};
class D : public B, public C
{
public:
virtual void test_d() {}
};
class E : public D
{
public:
virtual void test() {}
};
int main(void)
{
cout << "X size: " << sizeof(X) << endl;
cout << "Y size: " << sizeof(Y) << endl;
cout << "Z size: " << sizeof(Z) << endl;
cout << "A size: " << sizeof(A) << endl;
cout << "==========================" << endl;
cout << "B size: " << sizeof(B) << endl;
cout << "C size: " << sizeof(C) << endl;
cout << "D size: " << sizeof(D) << endl;
cout << "E size: " << sizeof(E) << endl;
return 0;
}
运行结果如下:
1. 存在多态的虚继承
class X、class Y、class Z和class A类之间的关系如下:
通过设置“项目->属性->C/C++->命令行中添加/d1reportSingleClassLayoutX”可在编译时查看class X的内存布局,class Y、class Z和class A依次类推,不过一次我只能设置一个(如果哪位大佬可以一次设置多个请留言告诉小弟),4个类的内存布局如下:
1> class X size(8):
1> +---
1> 0 | {vfptr}
1> 4 | m_x
1> +---
1> class Y size(12):
1> +---
1> 0 | {vbptr}
1> +---
1> +--- (virtual base X)
1> 4 | {vfptr}
1> 8 | m_x
1> +---
1> class Z size(16):
1> +---
1> 0 | {vfptr}
1> 4 | {vbptr}
1> +---
1> +--- (virtual base X)
1> 8 | {vfptr}
1> 12 | m_x
1> +---
1> class A size(20):
1> +---
1> 0 | +--- (base class Z)
1> 0 | | {vfptr}
1> 4 | | {vbptr}
1> | +---
1> 8 | +--- (base class Y)
1> 8 | | {vbptr}
1> | +---
1> +---
1> +--- (virtual base X)
1> 12 | {vfptr}
1> 16 | m_x
1> +---
可见,存在多态的虚继承时(大前提!!不存在多态的虚继承请看上一篇博客):
(1)派生类与基类不共享虚函数表指针,如果派生类添加了新的虚函数,派生类会在基类的基础上增加一个自己的虚函数表指针,例如class Z与class X,这就是为什么class Z会比class Y多一个指针大小的原因。
(2)在多层虚继承中,每一个派生类都会有自己的虚基类指针,虚基类指针只有一个并且是永远不会共享的,例如class A与class X,class A并没有从class Y和class Z中继承虚基类指针,只是继承了虚函数表指针,但是class A并没有生成自己的虚函数表指针,这是因为class A不是虚继承自class Y和class Z,因此派生类class A和基类class Y与class Z共享虚函数表指针(详见第二部分),且派生类class A里有自己单独的虚基类指针。
2. 存在多态的非虚多重继承
class B、class C、class D和class E类之间的关系如下:
4个类的内存布局如下:
1> class B size(4):
1> +---
1> 0 | {vfptr}
1> +---
1> class C size(4):
1> +---
1> 0 | {vfptr}
1> +---
1> class D size(8):
1> +---
1> 0 | +--- (base class B)
1> 0 | | {vfptr}
1> | +---
1> 4 | +--- (base class C)
1> 4 | | {vfptr}
1> | +---
1> +---
1> class E size(8):
1> +---
1> 0 | +--- (base class D)
1> 0 | | +--- (base class B)
1> 0 | | | {vfptr}
1> | | +---
1> 4 | | +--- (base class C)
1> 4 | | | {vfptr}
1> | | +---
1> | +---
1> +---
可见,在非虚继承的多重继承体系中,派生类与基类共享虚函数表指针,由于非虚继承,派生类内部没有虚基类指针。
总结
主要对存在多态的虚继承的内存布局进行了详细讨论,是对上一篇博客的深入研究,希望能帮助到对C++对象模型内存布局感兴趣的各位,小弟才疏学浅,如有错误还请大佬多多指教。