如何从 C++ 中的两次继承基 class 调用隐藏方法?
How to call a hidden method from two times inherited base class in C++?
考虑一个 class D
继承自两个 classes B
和 C
,每个继承非虚拟 class A
。在 A
中有一个方法 f
,在 B
中有一个相同的命名方法隐藏了 A
中的方法。我想从 D
对象的 B
-base class 调用 A::f()
,如下所示:
struct A { void f() {} };
struct B : A { void f() {} };
struct C : A {};
struct D : B, C {};
int main() { D{}.B::A::f(); }
不幸的是,它只适用于 MSVC,而 GCC 和 Clang 都会产生错误:
error: 'A' is an ambiguous base of 'D'
演示:https://gcc.godbolt.org/z/jY3v876hK
看起来 GCC/Clang 接受但完全忽略 B::A::f()
中的 B::
前缀。他们按照标准这样做对吗?
Are they right in doing so according to the standard?
是的。 A::
、B::A
或 D::B::A
中的嵌套名称说明符都用于相同的目的,将 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.
嵌套名称说明符没有命名成员的“路径”,它命名了 D
的基础。并且命名 A
导致歧义。
其他答案说明编译器正确的原因。
为了达到你想要的效果,你可以这样做:
int main() { static_cast<B&&>(D{}).A::f(); }
虽然有点丑。
考虑一个 class D
继承自两个 classes B
和 C
,每个继承非虚拟 class A
。在 A
中有一个方法 f
,在 B
中有一个相同的命名方法隐藏了 A
中的方法。我想从 D
对象的 B
-base class 调用 A::f()
,如下所示:
struct A { void f() {} };
struct B : A { void f() {} };
struct C : A {};
struct D : B, C {};
int main() { D{}.B::A::f(); }
不幸的是,它只适用于 MSVC,而 GCC 和 Clang 都会产生错误:
error: 'A' is an ambiguous base of 'D'
演示:https://gcc.godbolt.org/z/jY3v876hK
看起来 GCC/Clang 接受但完全忽略 B::A::f()
中的 B::
前缀。他们按照标准这样做对吗?
Are they right in doing so according to the standard?
是的。 A::
、B::A
或 D::B::A
中的嵌套名称说明符都用于相同的目的,将 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.
嵌套名称说明符没有命名成员的“路径”,它命名了 D
的基础。并且命名 A
导致歧义。
其他答案说明编译器正确的原因。
为了达到你想要的效果,你可以这样做:
int main() { static_cast<B&&>(D{}).A::f(); }
虽然有点丑。