2013-08-23 46 views
2

下面是示例代碼:Ambigulty同時調用重載操作

struct A 
{ 
    virtual int operator & (A &) { return 0; } 
}; 

struct B : public A {}; 
struct C : public A {}; 

struct D : public C, public B {}; 

int main() 
{ 
    D d; 
    std::cout << &d << std::endl; 
    return 0; 
} 

它完美地工作在VS 2008,但GCC無法編譯:

../src/TestCast.cpp: In function ‘int main()’: 
../src/TestCast.cpp:26:16: error: request for member ‘operator&’ is ambiguous 
../src/TestCast.cpp:15:14: error: candidates are: virtual int A::operator&(A&) 
../src/TestCast.cpp:15:14: error:     virtual int A::operator&(A&) 
make: *** [src/TestCast.o] Error 1 

據我看到的,它看起來對於運營商&按名稱重載,而不是通過簽名,因此它找到模糊的過載併產生錯誤。

問題是:Standard是否正確?如果沒有,哪一段描述呢?有什麼辦法讓GCC接受這個代碼(我的意思是,通過簽名而不是名字查找)。

順便說一句,我知道,如何解決這個代碼。我只想知道,爲什麼會出現錯誤。

+1

GCC是正確的。名稱查找發生在超載結束之前,並且它必須是明確的。由於D包含兩個A型子對象,它也有兩個'operator',一個在B中,另一個在C. – jrok

+0

令人驚訝的是,Clang 3.4(當前中繼)在C++ 11模式下接受這個代碼:http:// coliru.stacked-crooked.com/view?id=1315da921103f7ba233cc24f9ed0cd2c-76b69eb4e48bf39ce4212f2d8ff4a507 – rubenvb

+0

不幸的是,對於G ++,它不起作用...... :( –

回答

4

你造成的是鑽石繼承問題,你可以用虛擬繼承來解決它。

在A中,您已聲明虛擬operator&,它也在BC中定義。現在,這兩種方法都在D的內部定義,因爲您使用的是多重繼承。

從標準(10.1 多基類)。

不應將類指定爲派生類的直接基類不止一次。 [注意:一個類可以不止一次地作爲間接基類,可以是直接基類和間接基類。有限的 可以用這樣的一個類來完成的事情。基類的非靜態數據成員和成員函數不能在派生類的範圍內引用。但是,靜態成員枚舉 和類型可以明確地引用。 - 注完] [實施例:

甲基類SPECI音響ER不包含關鍵字虛擬,SPECI音響ES的非虛基類。基類 包含關鍵字virtual的類speci fi er,指定一個虛擬基類。對於派生類最多的類網格中的非虛擬基類的每個不同出現 ,最大派生對象(1.8)應該包含該類型的對應的不同基類子對象。對於每個不同的基類,它們是 指定的虛擬,最派生的對象應包含該類型的單個基類子對象。 [示例: 對於類型爲C的對象,類別格中的(非虛擬)基類L的每個不同的出現與類型C的對象中的不同L子對象一一對應。考慮到上面的C類定義爲 ,C類的一個對象將有兩個L類的子對象,如下所示。

L  L 
|  | 
A  B 
    \ /
    C 

圖3 - 非虛擬基 5在這種晶格,明確的合格音響陽離子可以用來指定哪些子對象是指。C :: f函數的主體可以引用每個L子對象的下一個成員: void C :: f(){A :: next = B :: next; } //格式良好 如果沒有A ::或B ::限定符,上述C :: f的定義將因爲含糊不清(10.2)而不合格。

0

我的標準已經找到:

3.4姓名查找[basic.lookup]

1名查找規則統一適用於所有名稱(包括的typedef名稱(7.1。 3),命名空間名稱(7.3)和類名稱(9.1)),只要語法允許在特定規則討論的上下文中使用這些名稱。名稱查找將名稱的使用與該名稱的聲明(3.1)相關聯。 名稱查找應找到一個明確的名稱聲明(見10.2)。如果名稱查找可能會將多個聲明與名稱關聯起來,如果它發現名稱是一個函數名稱;據說這些聲明構成了一組重載函數(13.1)。重載解析(13.3)在名稱查找成功後發生。只有在名稱查找和函數重載解析(如果適用)成功後纔會考慮訪問規則(第11章)。只有在名稱查找後,函數重載解析(如果適用)和訪問檢查已成功,纔是由表達式處理(第5節)中進一步使用的名稱聲明引入的屬性。

0

這段代碼實現的功能叫做diamond-inheritance問題。在編譯過程中簡要解釋它,編譯器發現operator &含糊不清,因爲它無法確定是調用B類繼承版本還是C類繼承版本。

爲了克服這種情況,聲明你的類定義爲

struct B : virtual public A {}; 

這使得只有一個類中可用的功能的副本D.