1

为什么这行得通

struct Base {
    virtual void visit(const A &) { };
    virtual void visit(const B &) { };
}

这在调用访问方法时抱怨歧义

template< typename T >
struct X {
    virtual void visit(const T &) { };
};

struct Base: X< A >, X< B > { };

这也显示了同样的问题:

struct Y {
   virtual void visit(const A &) { };
};

struct Z {
    virtual void visit(const B &) { };
};

struct Base: Z, Y { };

不知何故,它看起来像多重继承与虚函数签名混淆......

使用 gcc 版本 4.8.0 20130411(预发布)

4

1 回答 1

0

这里虚拟性是无关紧要的,并且 2 个基类是模板类这一事实是无关紧要的。具有相同问题的更简单的代码是:

struct A {
   void f(const A &) { }
};

struct B {
    void f(const B &) { }
};

struct Der: A,B { };

这里Der有两个继承的成员:A::f(const A &)B::f(const B &); 可以这样调用它们:

Der d;
d.A::f(d);
d.B::f(d);

不是这样:

d.f((A&)d); // error: ambiguous name lookup
d.f((B&)d); // error: ambiguous name lookup

成员函数重载决议不会按照您的想法工作(找到两者f然后保留具有兼容参数列表的那个)。

在 C++ 中,成员名称查找查找具有给定名称的所有非隐藏成员声明,​​因此在这里它找到A::f(const A &)and B::f(const B &),然后如果这些成员没有在同一个类中声明,它会立即失败。

您可以通过在同一类中添加 2 个声明来解决此问题:

struct Der: A,B {
    using A::f; // imports A::f(const A &)
    using B::f; // imports B::f(const B &)
};

然后你可以这样做:

Der d;
d.f((A&)d); // OK: Der::f(&A)

请记住:这纯粹是成员名称查找歧义。

于 2013-05-14T05:28:14.527 回答