Fedor
Fedor

Reputation: 21347

How to call a hidden method from two times inherited base class in C++?

Consider a class D inherited from two classes B and C, each of which inherits not-virtually class A. There is a method f in A, and the same named method in B hiding the method from A. I would like to call A::f() from B-base class of D object as follows:

struct A { void f() {} };
struct B : A { void f() {} };
struct C : A {};
struct D : B, C {};
int main() { D{}.B::A::f(); }

Unfortunately, it works only in MSVC, while both GCC and Clang produce the error:

error: 'A' is an ambiguous base of 'D'

demo: https://gcc.godbolt.org/z/jY3v876hK

It looks like GCC/Clang accept but completely ignore B:: prefix in B::A::f(). Are they right in doing so according to the standard?

Upvotes: 6

Views: 243

Answers (2)

Jeffrey
Jeffrey

Reputation: 11430

Other answers show why the compiler is correct.

In order to achieve what you want, you can do:

int main() { static_cast<B&&>(D{}).A::f(); }

It's a bit ugly, though.

https://gcc.godbolt.org/z/Mzs8rsdf5

Upvotes: 4

Are they right in doing so according to the standard?

Yes. The nested name specifier in A::, B::A, or D::B::A all serve the same purpose, to name the class A.

[basic.lookup.classref]

4 If the id-expression in a class member access is a qualified-id of the form

class-name-or-namespace-name::...

the class-name-or-namespace-name following the . or -> operator is first looked up in the class of the object expression ([class.member.lookup]) and the name, if found, is used. Otherwise it is looked up in the context of the entire postfix-expression.

The nested name specifier does not name "a path" to the member, it names a base of D. And to name A results in ambiguity.

Upvotes: 7

Related Questions