虛繼承是爲了消除多重繼承帶來的二義性。
以菱形繼承爲例:
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;
}