虚继承是为了消除多重继承带来的二义性。
以菱形继承为例:
class A
{
public:
int ma;
}
class B:public A
{
public:
B():A(){};
int mb;
}
class C:public A
{
public:
C():A(){}
int mc;
}
class D:public B,public C
{
public:
D():B(),C(){}
int md;
}
如下图:B和C的父类是A,D的父类是B和C
D的内存布局如下图所示:
可以看出D的内存布局中有两份A的数据,那当编译器给ma赋值时,是给B作用域下的ma还是C作用域下的ma,
这样就会产生二义性。
要消除二义性,就需要用到虚继承。把B类和C类继承A类继承都改为虚继承。
这时候A就成了B和C的虚基类。
这时候D的内存布局发生变化,把A::ma移到最底部,B::和C::多了一个虚基类指针(vbptr),它指向一个vbtable,这个表中存放的是从当前位置到虚基类成员变量(这指的是ma)的偏移量。通过偏移量可以找的虚基类成员变量的位置。
用了虚继承,我们必须在代码中给间接基类(这里指的A类)提供构造函数。代码就变成了如下结构:
class A
{
public:
int ma;
}
class B:virtual public A
{
public:
B():A(){};
int mb;
}
class C:virtual public A
{
public:
C():A(){}
int mc;
}
class D:public B,public C
{
public:
D():B(),C(),A(){}
int md;
}