[英]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
開始,構建Human
, Animal
,最后構建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
好的,讓我們記住這些規則再次閱讀輸出:
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 的那部分將被忽略。
Biology
虛擬繼承的所有基類在它們之間共享一個Biology
基實例。Biology
有一個實例每個Biology
。 您在每個類別中都有一個基礎,因此您有一個由Human
引入的Biology
實例(原則上與其他人共享)和一個由Animal
引入的實例(從未與任何其他基類共享)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.