2012-02-21 60 views
1

下面的代碼說明我的問題:使用虛擬繼承時可以避免冗餘基類初始化嗎?

struct Base { 
    Base(int n) : n(n) {} 

    virtual ~Base() = 0; 

    int n; 
}; 

Base::~Base() {} 

struct A : public virtual Base { 
    A(int n) : Base(n) {} 

    virtual ~A() = 0; 
}; 

A::~A() {} 

struct B : public virtual Base { 
    B(int n) : Base(n) {} 

    virtual ~B() = 0; 
}; 

B::~B() {} 

struct Test : public virtual A, public virtual B { 
    Test(int n) : Base(n), A(n), B(n) {} // how to avoid this duplication? 
}; 

int main() { 
    Test c(0); 
    (void)c; 
} 

正如你所看到的,Test構造函數必須初始化BaseAB明確。這是正常的嗎?還是有辦法避免冗餘?

+0

你的用例是什麼? – 2012-02-21 13:24:06

+0

實驗。 – StackedCrooked 2012-02-21 13:56:07

回答

2

沒有冗餘初始化。虛擬基類的構造函數僅由最派生類的構造函數調用一次。

更新該問題可以解釋爲兩件事情,(1)如何避免在運行時對構造函數的多餘調用和(2)如何避免編寫冗餘初始化列表。顯然作者的意思是(2)。我正在回答(1)。

+0

但有多餘的打字。 – StackedCrooked 2012-02-21 13:14:51

+0

作爲一個推論,值得思考1)在虛擬基類中是否需要一個非默認構造函數2)是否需要多重繼承。 – 2012-02-21 13:15:02

+0

查看更新。我可能誤解了你的問題:( – 2012-02-21 13:30:18

4
#include <assert.h> 

struct Base { 
    Base(int n) : n(n) {} 

    virtual ~Base() = 0; 

    int n; 

protected: 
    Base() { assert(false); } 
}; 

Base::~Base() {} 

struct A : public virtual Base { 
    virtual ~A() = 0; 
}; 

A::~A() {} 

struct B : public virtual Base { 
    virtual ~B() = 0; 
}; 

B::~B() {} 

struct Test : public virtual A, public virtual B { 
    Test(int n) : Base(n) {} // how to avoid this duplication? 
}; 

int main() { 
    Test c(0); 
    (void)c; 
} 
+0

一見鍾情這個看起來完全錯誤,但它確實有道理 – StackedCrooked 2012-02-21 13:18:12

+0

這很有創意 – ApprenticeHacker 2012-02-21 13:20:49

+0

它很有意義 - 'A'是抽象的,所以永遠不會是派生最多的虛擬繼承的'Base'只能由最大派生類型構造,所以它不會由'A'構造,如果有什麼東西在A中爲'Base'構造一個初始化器是無稽之談「首先。 – 2012-02-21 13:51:32

2

其一,沒有必要爲TestAB在您的方案几乎獲得,因爲無論A也不B似乎被用作基地lasses。

而且,是的,Base必須在最派生類被初始化。原因很簡單,即test的直接基類共享相同的Base子對象。爲了做到這一點,它必須由派生最多的階級在構建其中任何一個之前構建。
個人而言,我一直認爲AB也可以構造它,它是通過聲明順序作爲基類來確定的,並且使用另一個的構造函數。但是,如果兩者都調用不同的構造函數,那麼這會造成非常微妙的錯誤,而基類聲明順序的細微問題可能會引入令人驚訝的行爲更改。 (並不是說我們在語言的其他地方不會有這樣的問題,但少一點也許是件好事。)

但是請注意,儘管C++爲您提供了所有可能獲得的自由,但它通常是最好的如果虛擬基類抽象類,已經沒有構件數據,因此只有一個默認構造。由於這將被隱式調用,因此沒有一個派生類將不得不顯式調用構造函數。