【问题标题】:About multiple inheritance and ambiguity关于多重继承和歧义
【发布时间】:2016-05-07 19:41:06
【问题描述】:

在以下示例中:

class A {
public:
    virtual void f() { cout << "a" << endl; }
    virtual void h() { cout << "A" << endl; }
};
class s1 : public A {
public:
    virtual void f() { cout << "s1" << endl; }
};
class s2 : public A {
public:
    virtual void h() { cout << "s2" << endl; }
};
class GS : public s1, public s2 {
public:
};
int main()
{
    s1 *q = new GS;
    q->h();//no problem

    GS a;
    a.h();//error

}

为什么a.h(); 会给出歧义错误而q-&gt;h(); 却没有?

*q 没有GS 的实例,这会导致同样的歧义问题吗?

【问题讨论】:

    标签: c++ c++11 multiple-inheritance ambiguity


    【解决方案1】:

    您对多重继承的使用导致A 的两个实例出现在GS 中。当您使用S1 *q 访问GS 实例时,它遵循与S1 关联的A 实例。由于S1没有实现h(),所以q-&gt;h()的输出将是A本身提供的实现。

    如果你想让q-&gt;h() 使用S2 提供的实现,那么你需要使用虚拟继承创建一个菱形。这样做还可以消除使用a.h() 时的歧义,因为虚拟继承将导致A 的一个实例仅出现在GS 中。

    class s1 : virtual public A {
    public:
        virtual void f() { cout << "s1" << endl; }
    };
    class s2 : virtual public A {
    public:
        virtual void h() { cout << "s2" << endl; }
    };
    

    【讨论】:

    • 通过虚拟继承,GS 将始终寻找具有所需功能的最接近的基类?这里a.h(); 会在A::h() 之前转到s2::h()
    • 这是普通的虚拟接口规则。如果接口是虚拟的,则派生类实现会覆盖基类接口。
    【解决方案2】:

    名称查找基于静态类型而非动态类型。 (它必须是,因为它发生在编译时而不是运行时。)

    【讨论】:

      【解决方案3】:

      因为您的指针是s1 类型,所以编译器知道调用h()(继承自类A)。尝试使用GS 类型的指针,您也会收到指针错误。对于GS,您从s1s2 继承,这两个类都从A 继承,因此发现h() 的多个(2) 定义是模棱两可的。这是dreaded diamond

      【讨论】:

      • 您所指的可怕钻石并不完全是 OP 的问题。非常相似,但虚拟继承仍然是解决方案。
      • @AndyG 虚拟继承可能是“解决方案”。但不清楚是什么问题,或者是否存在问题。
      【解决方案4】:

      *q 不会给出歧义错误,因为它的类型是 s1*。这意味着编译器将调用s1::h,这是明确的。

      【讨论】:

        【解决方案5】:

        好的,这是因为当编译器计算 q->h() 时,q 在其范围内只有一个名为“h”的函数,因为它是 s1 类型。

        当编译器计算 a.h() 时,a 在其范围内有两个名为“h”的函数。来自 s1 的一个和来自 s2 的一个。

        编译器不知道你想使用哪一个,所以它会抛出一个错误。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-10-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-06-27
          • 1970-01-01
          • 1970-01-01
          • 2011-08-20
          相关资源
          最近更新 更多