C++ Multipath Inheritance : Why the access using Base class scope is non-ambiguous?

Viewed 83

I am studying C++ and while studying virtual inheritance, I came across following doubt:

class A {
public:
    int x;
    A() { x = 677; }
    A(int a) { 
        cout << "A con , x= " << a << endl;
        x = a;
    }
};
class B : public A {
public:
    B(int a) : A(a) { }
};
class C :public A {
public:
    C(int a) : A(a) { }
};
class D : public B, public C {
public:
    D(int a,int b) : B(a),C(b) { }
};
int main()
{
    D d(5,6);
    cout << d.A::x;  //prints 5 
 }

In line cout << d.A::x; It prints 5. Shouldn't this call be ambiguous and if not why it prints 5?

2 Answers

d.A::x; is indeed ambiguous. GCC and Clang report it as error, only MSCV fails to do so: https://godbolt.org/z/1zhjdE6a8.

There is a note in [class.mi] with an example of multiple inheritance stating that:

In such lattices, explicit qualification can be used to specify which subobject is meant. The body of function C​::​f can refer to the member next of each L subobject:

void C::f() { A::next = B::next; }      // well-formed

Without the A​::​ or B​::​ qualifiers, the definition of C​::​f above would be ill-formed because of ambiguity ([class.member.lookup]). — end note]

It is just a note, because it follows from [class.member.lookup] (which is a little more contrived to read and understand) that without the qualifier the member access is ambiguous. "ill-formed" implies that a conforming compiler must issue either an error or warning.

This is ambiguous according to both GCC and Clang, but MSVC compiles it (Godbolt)

You can solve it by using virtual inheritance for B and C if it makes sense to only have one instance of A in D or you can specify via which parent the call must access A::x if you need two distinct instances of A in D.

std::cout << d.B::x; // go through B to its A
std::cout << d.C::x; // go through C to its A

The above compiles on all 3 compilers without error, because it is unambiguous. It specifies through which intermediate class to access A::x.

Related