vsoftco
vsoftco

Reputation: 56547

Multiple inheritance ambiguous base class

Consider the code

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() {}

The compiler (g++5.1) warns that

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

I understand this, Base is duplicated in B.

  1. Why is there no warning for C? Doesn't C inherit from both A and Derived, which both inherit from Base?

  2. Why adding virtual

    struct Derived: virtual Base{};
    

results now in both B and C emitting warnings, live on 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{};

Upvotes: 10

Views: 3468

Answers (2)

Rexxar
Rexxar

Reputation: 1946

There are no ways to access unambiguously to Base members in "B" whereas it's possible in "C", as illustrated in the following code:

#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; 
}

Upvotes: 2

Brian Bi
Brian Bi

Reputation: 119144

In B, it's impossible to refer to members of the Base subobject inherited directly. Consider:

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
    }
};

In C this is not a problem. Both x's can be referred to using qualified names:

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

So the warning you get is one that only makes sense when a direct base is also inherited through another path.

For your second question, I couldn't reproduce the warning with C on Coliru with g++-5.1.

Upvotes: 2

Related Questions