11

使用 gcc 3.4.5 (mingw) 在我的一个类中出现以下编译错误:

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>。所以让我恼火的是这样一个想法,即由于某种原因,函数是模棱两可的,据我所知,它们不是。该addListener()方法针对不同的输入类型IListener<const SConsolePacket&>IListener<const SControlPacket&>. 用法是:

m_controller->addListener( m_model );

wherem_model是指向IRigidBody对象的指针,并且IRigidBody仅继承自IListener< const SControlPacket& >并且绝对不是继承自IListener< const SConsolePacket& >

作为健全性检查,我使用 doxygen 生成类层次结构图,doxygen 同意我的观点,IRigidBody这不是源自IListener< const SConsolePacket& >

显然我对 C++ 中继承的理解并不完全正确。我的印象是IListener<const SControlPacket&>andIListener<const SConsolePacket&>是两种不同的类型,并且函数声明

addListener(IListener<const SConsolePacket&>* listener)

addListener(IListener<const SControlPacket&>* listener)

声明两个独立的函数,它们根据输入参数的(不同的)不同类型做两件不同的事情。此外,我的印象是指向 anIRigidBody的指针也是指向 an 的指针,IListener<const SControlPacket&>并且通过调用addListener( m_model )编译器应该明白我正在调用上述两个函数中的第二个。

我什至尝试过m_model这样的投射:

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

但仍然得到那个错误。我一生都看不到这些功能是如何模棱两可的。任何人都可以阐明这个问题吗?

PS我知道如何通过这样做来强制函数明确:

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

我只是碰巧认为这是非常不可读的,我宁愿不必这样做。

编辑...开个玩笑。这显然不能解决问题,因为它会导致链接器错误:

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

1 回答 1

29

看起来你的情况是这样的:

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;
};

现在,这两个名称在同一个范围内,现在它们可以相互重载。查找现在将停止在控制器类,而不是深入到两个基类分支。

于 2009-08-21T17:12:25.207 回答