关于多重继承和歧义

About multiple inheritance and ambiguity

本文关键字:歧义 多重继承      更新时间:2023-10-16

在下面的示例中:

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->h();没有?

*q没有一个应该导致相同歧义问题的GS实例吗?

使用多重继承会导致GS中出现两个A实例。当您使用 S1 *q 访问GS实例时,它会跟随与S1关联的A实例。由于S1不实现h()q->h()的输出将是A本身提供的实现。

如果您希望q->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; }
};

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

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

好的,这是因为当编译器计算 q->h() 时,q 的作用域中只有一个名为"h"的函数,因为它的类型为 s1。

当编译器计算 a.h() 时,a 的作用域中有两个名为"h"的函数。来自 s1 的一个和来自 s2 的一个。

编译器不知道要使用哪一个,因此会引发错误。

*q不会

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