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?
CodePudding user response:
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::
orB::
qualifiers, the definition ofC::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.
CodePudding user response:
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
.