2009-08-21 61 views
9

我得到以下編譯錯誤在我的一個類,使用gcc 3.4.5(MinGW的)曖昧:請求成員`...」是在G ++

src/ModelTester/CModelTesterGui.cpp:1308: error: request for member `addListener' is ambiguous 
include/utility/ISource.h:26: error: candidates are: void utility::ISource<T>::addListener(utility::IListener<T>*) [with T = const SConsolePacket&] 
include/utility/ISource.h:26: error:     void utility::ISource<T>::addListener(utility::IListener<T>*) [with T = const SControlPacket&] 

希望你可以看到, ISource<T>是一個模板接口,它只是表明該對象可以是某個匹配類型爲IListener<T>的對象的通道。所以讓我厭煩的是這個想法,即由於某些原因,當我可以說,功能不明確時,它們不是。對於不同輸入類型IListener<const SConsolePacket&>IListener<const SControlPacket&>addListener()方法過載。的用法是:

m_controller->addListener(m_model); 

m_model是指向一個IRigidBody對象,IRigidBody僅從IListener< const SControlPacket& >繼承和從IListener< const SConsolePacket& >

作爲健全性檢查絕對不是,我使用的doxygen生成類層次圖和doxygen同意我的說法IRigidBody不是從IListener< const SConsolePacket& >

很明顯,我對C++中inheritence的理解並不完全正確。我的印象是IListener<const SControlPacket&>IListener<const SConsolePacket&>是兩種不同類型的下方,該函數聲明

addListener(IListener<const SConsolePacket&>* listener) 

addListener(IListener<const SControlPacket&>* listener) 

聲明兩個單獨的函數做取決於兩個不同的東西(不同)輸入的不同類型的參數。此外,我的印象是指向IRigidBody的指針也是指向IListener<const SControlPacket&>的指針,通過調用addListener(m_model),編譯器應該明白我正在調用上述兩個函數中的第二個函數。

我甚至嘗試鑄造m_model這樣的:

m_controller->addListener(
     static_cast<IListener<const SControlPacket&>*>(m_model)); 

,但仍然得到這個錯誤。我不能在我的生活中看到這些功能是如何模糊的。任何人都可以解釋這個問題嗎?

P.S.我知道如何做這個給力的功能,是未曖昧:

m_controller->ISource<const SControlPacket&>::addListener(m_model); 

我恰好覺得是非常unreadible,我不希望有這樣做。

編輯...只是開玩笑。這因爲它會導致鏈接錯誤顯然不能解決問題:

CModelTesterGui.cpp:1312: undefined reference to `utility::ISource<aerobat::SControlPacket const&>::addListener(utility::IListener<SControlPacket const&>*)' 
+0

SControlPacket和SConsolePacket之間的關係是什麼? – GRB 2009-08-21 16:59:28

+0

請問爲什麼最後一行'm_controller-> ISource :: addListener(m_model);'消除了這個調用的歧義?如果函數超載,它們應該在同一個類中。這些職能在哪裏申報? – 2009-08-21 17:01:49

+0

@GRB沒有關係。兩者都是從無到有的結果。 @litb我錯了。它使它編譯,但事實證明,當鏈接器去嘗試找到純虛擬的ISource <...> :: addListener(...)時,會導致鏈接錯誤。現在我很困惑。當你說聲明我假設你的意思是定義。它們被定義在來自IController的concerete類中。 – cheshirekow 2009-08-21 17:12:31

回答

20

看起來像你的情況是這樣的:

struct A { 
    void f(); 
}; 

struct B { 
    void f(int); 
}; 

struct C : A, B { }; 

int main() { 
    C c; 
    c.B::f(1); // not ambiguous 
    c.f(1); // ambiguous 
} 

中的F的第二個電話是模糊的,因爲在仰視該名稱在兩個不同的基類作用域中查找函數。在這種情況下,查找是不明確的 - 它們不會互相超載。一個修復方法是爲每個成員名稱使用using聲明。查找將在C範圍內找到名稱,並且沒有進一步查找:

struct C : A, B { using A::f; using B::f; }; 

現在,呼叫會發現兩種功能,做重載決議,並發現一個以int將適合。結轉到你的代碼,這將意味着你必須做類似下面的

struct controller : ISource<const SConsolePacket&>, ISource<const SControlPacket&> { 
    using ISource<const SConsolePacket&>::addListener; 
    using ISource<const SControlPacket&>::addListener; 
}; 

現在,這兩個名字都在相同的範圍內,現在他們可以重載對方。查找現在停止在控制器類,而不是進一步深入到兩個基礎級分支。

+0

好!那就是那些東西的用途。我不認爲我真的理解使用聲明(這是不真正理解名稱查找的結果)。非常感謝你。作爲說明,我實際上將使用聲明放在IController接口中。我認爲這是適合它的地方。 – cheshirekow 2009-08-21 17:21:01

+0

至少在g ++中,不允許使用兩個。您可以在派生類C中選擇A :: f或B :: f。 – Dingle 2011-05-24 03:14:10

+0

謝謝!一如既往的一個非常簡潔明瞭的答案:D – 2013-02-27 19:24:26

相關問題