虛函數繼承和虛繼承是完全不同的兩個概念。
虛函數繼承是解決多态性的,當用基類指針指向派生類對象的時候,基類指針調用虛函數的時候會自動調用派生類的虛函數,這就是多态性,也叫動态編聯。
虛繼承就是為了節約記憶體,他是多重繼承中的特有的概念。适用于菱形繼承形式。
比如B繼承于A、C繼承于A、D繼承于B和C,顯然D會繼承兩次A(圖1)。是以,為了節省空間,可以将B、C對A的繼承定義為虛拟繼承,而A就成了虛拟基類(圖2)。代碼如下:
A A A
\ / / \
B C B C
\ / \ /
D D
(圖1) (圖2)
class A;
class B:vitual public A;
class C:vitual public A;
class D:public B,public C;
虛繼承的時候子類會有一個指向自己虛函數表的指針,同時也會加入一個指向父類的虛類指針,然後還要包含父類的所有内容。
虛繼承時如果子類父類都有虛函數,那麼它會重建立立一張虛表,不包含父類虛表的内容;而在普通的繼承中卻是在父類虛表的基礎上建立一張虛表。這就意味着如果虛繼承中子類父類都有各自的虛函數,在子類裡面就會有兩個虛函數表指針,一個指向父類的虛表,一個指向子類的虛表,而普通的繼承隻有一個指向子類虛表的指針。代碼說明:
class A
{
int k;
public:
virtual void aa(){};
};
class B:public virtual A
{
int j;
public:
virtual void bb(){};
};
class C:public virtual B
{
int i;
public:
virtual void cc(){};
};
int main()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
cout << sizeof(C) << endl;
system("pause");
return ;
}
輸出結果為:8、20、32。
怎麼來的呢?類A中包含一個整型變量k(4位元組),一個虛表指針(4位元組),是以一共8位元組。類B中,一個整型變量j(4位元組),一個虛表指針(4位元組),因為B虛繼承于A,所有會有一個指向類A的虛類指針(4位元組),同時還要包含類A中的整型變量k(4位元組)以及類A的虛表指針(4位元組),是以一共20位元組。類C同理。
如果将上述代碼改為普通繼承,那麼輸出結果為:8、12、16。沒有虛類指針,也不會有多個虛表指針。