5

在下面的代碼中,我試圖創建一個Leaf對象obj以查看多層繼承中的構造函數順序,但是我發現obj的結構和構造函數調用在這種情況下有點奇怪。如何在虛擬繼承中構建直接基礎?

#include<iostream> 
using namespace std; 
class Base1 { 
public: 
    Base1(void) { 
     cout << "class Base1" << endl; 
    } 
}; 
class Base2 { 
public: 
    Base2(void) { 
     cout << "class Base2" << endl; } 
}; 
class Level1 : public Base2, virtual public Base1 
{ 
public: 
    Level1(void) 
    { 
     cout << "class Level1" << endl; 
    } 
}; 

class Level2 : public Base2, virtual public Base1 
{ 
public: 
    Level2(void) 
    { 
     cout << "class Level2" << endl; 
    } 
}; 

class Leaf :virtual public Level2, virtual public Level1 
{ 
public: 
    Leaf(void) 
    { 
     cout << "class Leaf" << endl; 
    } 
}; 


int main(void) 
{ 
    Leaf obj; 
    return 0; 
} 

隨着顯示構造函數的輸出要求:

class Base1 
class Base2 
clase Level2 
class Base2 
class Level1 
class Leaf 

但是obj的在節目結束的結構實際上就是:

obj 
--Level2 
----Base2 
----Base1 
--Level1 
----Base2 
----Base1 
--Base1 

我知道objBase1是虛擬繼承,但在構建obj時,Level2Level1也需要構建,這導致在其每個結構中都有Base1。但整個構建過程只調用一次Base1構造函數。我無法解釋這一點。這是否意味着Base1Level2Level1裏面objBase1共享相同的數據,直接屬於obj

+3

虛擬繼承的重點在於您只有*一個虛擬基礎子對象。 –

+0

你知道,與C中不同的是,在C++中,空參數列表是簡單的(),對吧? – curiousguy

回答

4

但整個構建過程只調用一次Base1構造函數。我無法解釋這一點。

解釋是Base1是層次結構中所有類的虛擬基礎。這正是虛擬基礎以及它們的用途:共享公共基類實例。從cppreference

行情對於被指定的虛擬每個不同的基類,最派生對象包含該類型的僅一種鹼基類子對象,即使類出現在繼承層次多次(如只要它每次都是虛擬繼承的)。

所有虛擬基子對象的任何非虛基類子對象之前初始化,所以只有最派生類中調用它的成員初始化列表中的虛擬基礎的構造函數:

以虛擬繼承進去,你的結構圖可以被認爲是這樣的:

obj 
--Level2 
----Base2 
----+-------Base1 
--Level1 // 
----Base2// 
----+----//
--+-------/ 

這是否意味着內部的obj股價在2級以及1級的有基礎1基礎1相同的數據直接屬於OBJ?

是的。在obj的整個結構中只有一個Base1實例。

1

這是否意味着Base2在Level2和Level1內部obj與Base1直接屬於obj共享相同的數據?

是的,還有的Base1只有一個子對象,並通過Level2Level1基子在Leaf類共享。

下面是與例如從標準的說明,$ 10.1/6多個基類[class.mi](強調礦)

對於另一示例,

class V { /* ... */ }; 
class A : virtual public V { /* ... */ }; 
class B : virtual public V { /* ... */ }; 
class C : public A, public B { /* ... */ }; 

爲的目的c類型C,類型爲V的單個子對象是 由每個基本子對象c共享,該子對象具有虛擬基類 類型V。鑑於以上定義的類別C,類C的對象將 具有V的一個子對象,如下所示。