天天看點

C++虛函數繼承與虛繼承

虛函數繼承和虛繼承是完全不同的兩個概念。

虛函數繼承是解決多态性的,當用基類指針指向派生類對象的時候,基類指針調用虛函數的時候會自動調用派生類的虛函數,這就是多态性,也叫動态編聯。

虛繼承就是為了節約記憶體,他是多重繼承中的特有的概念。适用于菱形繼承形式。

比如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。沒有虛類指針,也不會有多個虛表指針。

繼續閱讀