C++钻石继承中显式访问B::A::a仍有歧义的原因及标准依据
你尝试编译的代码如下:
struct A{ int a; }; struct B : A{}; struct C : A{}; struct D: B,C{ void f(){ ++B::A::a; } }; int main() {}
显式指定B::A::a仍触发歧义的原因
核心原因是C++的命名查找规则中,B::A不会被识别为“B基类路径下的A子对象”,只会被解析为类型查找:编译器会在B的作用域里查找A,最终找到的是顶层的::A类型,所以B::A::a和直接写A::a没有任何区别。
此时编译器仍然无法确定要访问的是D实例中两个A子对象(一个来自B继承链,一个来自C继承链)中的哪一个的a成员,自然会报歧义错误。
如果要明确指定访问B继承链上的A子对象的a,正确的写法有两种:
- 写法1:指定成员所属的直接父类路径:
++B::a; - 写法2:显式转换当前实例到B类型再访问:
++static_cast<B&>(*this).a;
以上两种写法都能让编译器唯一确定要访问的子对象,编译可以正常通过。
对应的C++标准定义
该行为在C++标准的**[class.member.lookup](成员名称查找)**章节明确定义:
- 嵌套名说明符(
::左侧的部分)如果为类名,执行的是类型名称查找,不会隐含绑定到某个特定的基类子对象 - 如果成员查找的最终结果对应多个不同基类子对象中的同名成员,程序属于格式错误,编译器必须报歧义错误。
内容的提问来源于stack exchange,提问作者Karen Baghdasaryan
相关产品推荐
相关产品推荐

