2012-10-16 28 views
1

從Java後臺我從來沒有遇到過鑽石問題,即作爲http://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem當C++遇到鑽石問題

詳細描述,但如果出現此問題將在C++運行時抱怨多繼承會導致覆蓋問題即將會發生什麼情況或者它是隨機的超類方法的實現將被調用?

我已閱讀文章的「緩解」部分,但沒有完全理解它。

+0

你爲什麼不試試呢? – Nasreddine

+1

本文沒有解釋「緩解」*部分下會發生什麼? –

+2

您是否閱讀過您鏈接到的文章?它明確地說,「C++需要明確指出要使用的特徵是從哪個父類調用,即'Worker :: Human.Age'。」 (我承認,寫得不是很好,但如果你閱讀並且不理解它,那麼你應該這樣說,否則你可能會得到一個答案,只是引用你已經無法理解的文本! ) – ruakh

回答

2

編譯器提供的服務將搭上程序通過診斷任何歧義遇到鑽石問題的例子。

一個解決方案是消除歧義。

struct B { 
    int bar; 
}; 

struct D1 : B {}; 
struct D2 : B {}; 

struct E : D1, D2 {}; 

int main() { 
    E e; 
    e.D1::bar = 1; // explicitly set D1::bar, not D2::bar. 
} 

或者,如果你想訪問基子對象爲:B *b = new E;這是不明確的,你是否希望從D1或D2基礎子對象這可以通過使用明確的名稱限定指成員時完成。對這些中間類型之一使用明確的強制轉換解決了歧義。

B *b = static_cast<D2*>(new E); 

另請注意,從B *到E *的向下投射不可能靜態進行;編譯器不知道指向哪個B,因此它不會靜態知道如何調整指針以返回E.這就是dynamic_cast成爲必要的地方。

E *e = new E; 
B *b1 = static_cast<D1*>(e); 
B *b2 = static_cast<D2*>(e); 
assert(b1 != b2); 
assert(dynamic_cast<E*>(b1) == dynamic_cast<E*>(b2)); 
assert(e == dynamic_cast<E*>(b1)); 

另一種解決方案是避開虛擬繼承的問題,從而避免了同一類型的多個基本子對象。

struct B { 
    virtual void foo() = 0; 
    virtual ~B() = default; 
    int bar; 
}; 

struct D1 : virtual B {}; 
struct D2 : virtual B {}; 

struct E : D1, D2 { 
    virtual void foo() override { 
     bar = 1; // no ambiguity because there's only a single B base sub-object 
    } 
}; 
1

該錯誤被編譯器捕獲。這裏是http://www.parashift.com/c%2B%2B-faq-lite/mi-diamond.html

class Base { 
public: 
protected: 
    int data_; 
}; 

class Der1 : public Base { }; 

class Der2 : public Base { }; 

class Join : public Der1, public Der2 { 
public: 
    void method() 
    { 
     data_ = 1; //g++ error: reference to ‘data_’ is ambiguous 
    } 
}; 

int main() 
{ 
    Join* j = new Join(); 
    Base* b = j; //g++ error: ‘Base’ is an ambiguous base of ‘Join’ 
}