关于多重继承和歧义

About multiple inheritance and ambiguity

在下面的例子中:

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 的实例会导致同样的歧义问题吗?

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

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

编译器不知道您要使用哪一个,因此会抛出错误。

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

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

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

您使用多重继承导致 A 的两个实例出现在 GS 中。当您使用 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; }
};