簡體   English   中英

混合基類的虛擬和非虛擬繼承

[英]Mixing virtual and non-virtual inheritance of a base class

這是代碼:

struct Biology
{    
    Biology() { cout << "Biology CTOR" << endl; }
};

struct Human : Biology
{    
    Human() { cout << "Human CTOR" << endl; }
};

struct Animal : virtual Biology
{
    Animal() { cout << "Animal CTOR" << endl; }
};

struct Centaur : Human, Animal
{
    Centaur() { cout << "Centaur CTOR" << endl; }
};

int main()
{   
   Centaur c;

   return 0;
}

此代碼打印:

Biology CTOR
Biology CTOR
Human CTOR
Animal CTOR
Centaur CTOR

為什么?

因為我們創建了一個Centaur對象,所以我們從構建Centaur開始,構建HumanAnimal ,最后構建Centaur (我們從較少派生到派生最多)。

讓我們從Human開始: Human繼承了Biology ,所以我們先調用Biology的構造函數。 既然已經構建了Human的基類,我們終於可以構建Human本身了。 但相反, Biology再次被構建!

為什么? 幕后發生了什么?

請注意,這完全是故意讓Animal虛擬繼承Biology ,同時也是故意讓Human非虛擬繼承Biology

我們正在以錯誤的方式解決可怕的鑽石人類和動物都應該實際上繼承生物學來完成這項工作。

我只是好奇。

另外,請參閱此代碼:

struct Biology
{    
    Biology() { cout << "Biology CTOR" << endl; }
};

struct Human : virtual Biology
{
    Human() { cout << "Human CTOR" << endl; }
};

struct Animal : Biology
{    
    Animal() { cout << "Animal CTOR" << endl; }
};

struct Centaur : Human, Animal
{
    Centaur() { cout << "Centaur CTOR" << endl; }
};

int main()
{   
   Centaur c;

   return 0;
}

在這里,我們將Human虛擬地從Biology繼承,而Animal設置為以“經典方式”繼承。

但這一次,輸出不同:

Biology CTOR
Human CTOR
Biology CTOR
Animal CTOR
Centaur CTOR

這是因為Centaur首先Human繼承然后Animal繼承。

如果順序是相反的,我們將獲得與之前相同的結果,在第一個示例中 - 連續構造兩個Biology實例。

這是什么邏輯?

請嘗試解釋你的方式,我已經檢查了大量關於這個的網站。 但似乎沒有一個能滿足我的要求。

從輸出中可以清楚地看出,兩個Biology對象已被實例化 那是因為你只做了一個繼承virtual 兩個基類實例是可怕的菱形問題中歧義的原因,解決方案是(如我們所知)使Biology兩個繼承成為virtual

層次結構回顧:

Biology  Biology
   |       |     # one and only one inheritance virtual
 Human   Animal
    \     /
    Centaur

好的,讓我們記住這些規則再次閱讀輸出:

  • 基類在派生類之前構造。
  • 基類是按照它們在base-specifier-list 中出現的順序構造的。
  • 虛擬基類由最派生的類在非虛擬基類之前構造- 請參閱this

1輸出- Animal virtual從LY繼承Biology

Biology CTOR     # virtual base class inherited from Animal
Biology CTOR     # non-virtual base class of Human
Human CTOR       # Human itself
Animal CTOR      # Animal's virtual base class already constructed
Centaur CTOR

第二個輸出 - Human virtual繼承自Biology

Biology CTOR     # virtual base class inherited from Human
Human CTOR       # Human's virtual base class already constructed
Biology CTOR     # non-virtual base class of Animal
Animal CTOR      # Animal itself
Centaur CTOR

更多信息標准段落[class.base.init]/10

在非委托構造函數中,初始化按以下順序進行:

— 首先,並且僅對於最派生類 (1.8) 的構造函數,虛擬基類按照它們出現在基類的有向無環圖的深度優先從左到右遍歷中出現的順序進行初始化,其中“左-to-right” 是基類在派生類base-specifier-list 中的出現順序。

— 然后,直接基類按照它們出現在base-specifier-list中的聲明順序進行初始化(無論mem-initializers的順序如何)。

...

非虛擬繼承是一種排他關系,就像成員資格一樣。 一個類可以是給定完整對象中另一個類的非虛擬基類。

這意味着一個類可以覆蓋非虛基類的虛函數而不會引起沖突或問題。

構造函數也可以可靠地初始化非虛擬基類。

只有虛擬基類可以是一個完整對象的許多間接基類的直接基類。 由於可以共享虛擬基類,因此覆蓋程序可能會發生沖突。

構造函數可以嘗試初始化 ctor-init-list 中的虛擬基子對象,但如果進一步派生該類,則 ctor-init-list 的那部分將被忽略。

  1. Biology虛擬繼承的所有基類在它們之間共享一個Biology基實例。
  2. 所有的基類,從繼承非虛擬Biology有一個實例每個Biology

您在每個類別中都有一個基礎,因此您有一個由Human引入的Biology實例(原則上與其他人共享)和一個由Animal引入的實例(從未與任何其他基類共享)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM