2014-09-24 37 views
0

我遇到過這個讓我困惑的問題。複雜的構建順序 - 涉及虛擬繼承

這個代碼是:

struct B1 { B1(){std::cout << "B1\n";} }; 
    struct V1 : public B1 { V1(){std::cout << "V1\n";} }; 
    struct D1 : virtual public V1 {D1(){std::cout << "D1\n";} }; 

    struct B2 {B2(){std::cout << "B2\n";} }; 
    struct B3 {B3(){std::cout << "B3\n";} }; 
    struct V2 : public B1, public B2 {V2(){std::cout << "V2\n";} }; 
    struct D2 : public B3, virtual public V2 {D2(){std::cout << "D2\n";} }; 
    struct X : public D1, public D2 { }; 

問:什麼是建築X的順序?

這裏是我與簡化IT

enter image description here

首先,我想回答這個事實,認爲沒有虛繼承這個問題的目的是構建一個圖。關鍵字virtualpublic代替我會得到

B1,V1,D1, [B3,B1,B2,V2,D2] , X 

但是我不知道,當虛擬繼承走來我會如何處理這個問題。它提到的代碼。我讀到它的解決方法完全一樣,但virtual bases優先。這裏有哪些虛擬基地?有關如何解決這個問題的任何建議?

+0

該圖不正確,兩個'B1'實例是分開的。 – 2014-09-24 05:58:14

+0

我不確定如果'V1'是'虛擬公共B1'但是'V2'是(非虛擬)'public B1',會發生什麼情況! – 2014-09-24 05:59:46

+0

@MattMcNabb虛擬的虛擬構建器實際上由'X'的構造器構造,非虛擬構造器通過V2的構造器非虛擬構造;你最終得到兩個'B1'子對象。 – 2014-09-24 06:55:34

回答

2

這裏的規則(§12.6.2[class.base.init]/P11):

在非委託構造,在 初始化前進順序如下:

  • 首先,僅對於派生類(1.8)的構造函數,虛擬基類按其在 基類的有向無環圖的深度優先從左到右的遍歷中出現的順序進行初始化,其中「從左到右「是的出現順序派生類中的基類基指定符列表
  • 然後,直接基類在聲明的順序,因爲它們出現在鹼說明符列表(不管 MEM-初始化的順序)進行初始化。
  • 然後,非靜態數據成員將按照它們在類定義中聲明的順序進行初始化(不管 成分初始化程序的順序如何)。
  • 最後,執行構造函數體的複合語句

所以,如果V1和V2是虛擬的基礎,然後建設進入V1 - > V2 - > D1 - > D2 - > X的複合語句。 V1的構造函數將首先構造一個B1,然後執行它的主體。 V2的構造函數將構造一個B1和一個B2,然後執行它的主體。 D2的構造函數將在執行它的主體之前構造一個B3。 (因爲D1和D2都不是最派生類,所以它們的構造函數不會構造虛擬基類V1或V2)。因此,整體打印順序爲B1→V1→B1→B2→V2→D1→ B3→D2→X.

如果V1和V2不是虛擬鹼基,那麼X的構造就是D1→D2→X. D1具有單個直接基底V1,V1具有單個直接基底B1 ,所以你得到第一部分B1 - > V1 - > D1。同樣的,你爲第二部分構造B3→B1→B2→V2→D2,所以總體順序爲B1→V1→D1→B3→B1→B2→V2→D2-> > X.

+0

由於D2不是派生類最多的,所以'D2'沒有調用'V2'的構造函數嗎? – 0x499602D2 2014-09-24 03:59:33

+0

@ 0x499602D2在虛擬基礎情況下?是。 – 2014-09-24 04:04:46

+0

第一個要點不明確,是否說圖中出現的所有虛擬基類都是先初始化的;或者只是'X'直接繼承的那些? – 2014-09-24 05:52:28