多重继承歧义基class

Multiple inheritance ambiguous base class

考虑代码

struct Base{};
struct Derived: public Base{};

struct A: public Base{};

struct B: public A, public Base{};

struct C: public A, public Derived{}; // why no ambiguity here?

int main() {}

编译器 (g++5.1) 警告说

warning: direct base 'Base' inaccessible in 'B' due to ambiguity struct B: public A, public Base{};

我明白了,BaseB 中重复了。

  1. 为什么C没有警告? C 不是同时继承自 ADerived,它们都继承自 Base 吗?

  2. 为什么要加virtual

    struct Derived: virtual Base{};
    

结果现在 BC 发出警告,继续 Wandbox

warning: direct base 'Base' inaccessible in 'B' due to ambiguity struct B: public A, public Base{};

warning: direct base 'Base' inaccessible in 'C' due to ambiguity struct C: public A, public Derived{};

B中,不可能引用直接继承的Base子对象的成员。考虑:

struct Base {
    int x;
};

struct B: public A, public Base {
    void foo() {
        int& x1 = A::x; // OK
        int& x2 = x; // ambiguous
        // no way to refer to the x in the direct base
    }
};

C 这不是问题。两个 x 都可以使用限定名称来引用:

struct C: public A, public Derived {
    void foo() {
        int& x1 = A::x; // OK
        int& x2 = Derived::x; // OK
    }
};

因此,您收到的警告只有在 直接 基数也通过另一条路径继承时才有意义。

关于你的第二个问题,我无法在 Coliru 上用 g++-5.1 重现 C 的警告。

在 "B" 中无法明确访问 Base 成员,而在 "C" 中是可能的,如以下代码所示:

#include <iostream>

using namespace std;

struct Base
{
    void print()
    {
        cout << "Base" << endl;
    }
};

struct Derived : public Base {};

struct A : public Base
{
    void print()
    {
        cout << "A" << endl;
    }
};

struct B : public A, public Base
{
    void print()
    {
        A::print();

        //error (ambiguous), no way to access to Base::print => warning
        //Base::print();
    }
};

struct C : public A, public Derived
{
    void print()
    {
        A::print();
        Derived::print(); // Not Ambiguous, it's the Base inherited by 'Derived' which is used.
        // Still an error but you can access print indirectly through "Derived" => no warning needed
        //Base::print();
    }
};

int main() 
{
    B b;
    b.print();

    C c;
    c.print();

    return 0; 
}