2009-08-21 59 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

相关问题