上一篇已经分析了基本结构体、C++简单对象和加上一般的继承之后的各种情况,这篇文章将主要在有虚继承时,C++对象的内存又是怎样分配的。
虚继承
虚继承解决了从不同途径继承的类具有共同基类的问题,使得共同基类只有一份拷贝。解决了二义性的问题,也节省了内存。
虚继承的一般类图如下所示:
sizeof(Derived) = 40 字节。经过分析,可以得到Derived类在内存中的存储结构示意图为:
总结:
- 各部分在内存中的存放顺序为先父类、后子类、最后公共基类,即先存放Base1、Base2,然后是Derived,最后才是Base类
- 对于虚拟继承,子类中会增加一个vbptr指针,它指向的值要么是0,要么是-4,表示公共基类相对于子类的偏移,也即Base类相对于Derived类的偏移。当Base类中有虚函数时,为-4;否则为0。
- 在VS编译器中,子类和公共基类之间会通过一个NULL指针分隔开。在其它编译器中可能没有这个字段
对于每个类的虚函数表可以依次分析:
- 首先是Base类,Base类的ff()函数首先被Base1覆盖,然后又被Derived类覆盖,Base类的gg()函数并未被覆盖,因此Base类的虚函数表中指向的虚函数分别为:Derived::ff()、Base::gg()。
- 然后是Base1类,Base1类原本定义了两个虚函数,但是ff()函数是覆盖了父类Base中的函数,因此不在Base1的虚函数表中,只有bf1()。同时子类Derived中新定义了一个hh()虚函数,要插入到内存中的第一个虚函数表,因此会插入到Base1类的虚函数表中,因而Base1类中会有Base1::bf1()、Derived::hh()两个函数
- 最后是Base2类,只有Base2::bf2()一个虚函数。
简单的验证代码如下所示:
typedef void (*Fun) (void );
class Base{
public: