2013-01-21 60 views
3

我想一些幫助解釋這個phenomenom:爲什麼這段代碼不起作用? (C++ OOP)公共繼承

#include <iostream> 
using namespace std; 

class A 
{ 
public: 
    void m() {cout<<"A::m "<<this<<endl;}; 
}; 

class B1: public A 
{ 
public: 
    void m() {cout<<"B::m "<<this<<endl;}; 
}; 

class B2: public A ,public B1 
{ 
}; 

class D : public B2 
{}; 

int main() 
{ 
    B2 b; 
    D d; 
    A* a = &b; // Row 27 
    //error: a = &d; Base class 'A' is ambiguous // Row 28 
    return 0; 
} 

爲什麼代碼在Row27工作,但在Row28犯規的代碼? 提前致謝!我很想知道虛擬繼承,我只是想知道Row27和Row28之間有什麼區別 - 爲什麼一個拋出一個編譯錯誤,而另一個不是?

+2

http://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem – Pubby

+0

它不適用於此,否則Row27也不起作用!第27行和第28行有什麼區別? – YoniXw

+0

你使用什麼編譯器?第27行不會在這裏編譯 –

回答

1

因爲您使用的是非虛擬繼承來源於A,該類型在D類型的每個對象中間接創建了類型爲A的兩個子對象。編譯器無法消除在執行指向派生指針到基準轉換時引用的哪個子對象,併發出錯誤。

爲了具有用於D類型的對象生成的A類型的僅一個子對象,則必須從A虛擬沿着繼承路徑,這使得D使繼承從A派生:

class B1: virtual public A 
{ 
    // ... 
}; 

class B2: virtual public A, public B1 
{ 
}; 

編輯:

我試圖編譯你的例子在Visual Studio 2010 SP1,這給我一個警告關於的定義:

class B2: public A, public B1 
{ 
}; 

1>sotest.cpp(18): warning C4584: 'B2' : base-class 'A' is already a base-class of 'B1' 
1>   sotest.cpp(6) : see declaration of 'A' 
1>   sotest.cpp(11) : see declaration of 'B1' 

換句話說,由於某種原因,VC10似乎認爲從A多餘的繼承和忽略它。這就是爲什麼分配A* a = &b;的作業:class B2實際上只從A繼承(通過B1)。 D也是如此,因爲VC10可能沒有要忽略的冗餘繼承,並且D有效地從A有效繼承兩次(通過B1和通過B2)。

我忽略了VC10行爲的原因,我不知道是否有編譯器選項來抑制這種行爲。值得注意的是,GCC 4.7.2和Clang 3.2 拒絕編譯作業A* a = &b;

+0

那麼爲什麼Row27中的代碼工作?爲什麼它不需要虛擬繼承!? B2和'D'有相同數量的'A'! – YoniXw

+0

@ user1997873:它真的有用嗎?我只是在GCC 4.7.1和Clang 3.2上試過它,除非我使用虛擬繼承,否則我會遇到編譯器錯誤。你在用什麼編譯器? –

+0

Visual Studio C++ 2010 Express – YoniXw

1

對於未來用戶看來:

我剛在GCC 4.7.1和3.2鏘,我得到一個編譯錯誤,除非我用虛擬繼承。你在用什麼編譯器? - Andy Prowl

VS2010的確編譯,但發出警告,表明它忽略了B2從A的繼承。這就是27行的原因。我認爲這是VS2010的奇怪行爲,我不知道是否有辦法將其關閉(除了將所有警告視爲錯誤) - Andy Prowl

謝謝@Andy Prowl。

相關問題