我在我的一个类中使用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>的对象的informer.让我烦恼的是这个想法,由于某种原因,功能是模棱两可的,据我所知,它们不是.对于不同的输入类型,重载addListener()方法IListener< const SConsolePacket&>和IListener< const SControlPacket&>.用法是:
m_controller->addListener( m_model );
其中m_model是指向IRigidBody对象的指针,而IRigidBody仅继承自IListener< const SControlPacket& >并且肯定不是来自IListener< const SConsolePacket& > 作为一个完整性检查,我使用doxygen来生成类层次结构图,并且doxygen同意我IRigidBody不是从IListener得到的< const SConsolePacket& > 显然,我对c中遗传的理解并不完全正确.我的印象是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) );
但仍然得到那个错误.我不能为我的生活看到这些功能是如何模棱两可的.任何人都可以解释这个问题吗?
附:我知道如何通过这样做强制该函数不明确:
m_controller->ISource<const SControlPacket&>::addListener( m_model );
我碰巧认为这是非常不可读的,我宁愿不必这样做.
编辑……开个玩笑.这显然无法解决问题,因为它会导致链接器错误:
CModelTesterGui.cpp:1312: undefined reference to `utility::ISource<aerobat::SControlPacket const&>::addListener(utility::IListener<SControlPacket const&>*)'
解决方法:
看起来你的情况是这样的:
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;
};
现在,这两个名称在同一范围内,现在它们可以相互重载. Lookup现在将停在控制器类,而不是进一步深入两个基类分支.