关于虚拟继承程序输出结果的困惑
嘿,我来帮你拆解这段虚拟继承代码的输出逻辑,先给你看程序实际运行的输出结果,再一步步讲清楚原因:
e.A::m = 5005 e.D::m = 6006 e.m = 303
先理清你的继承结构
先把继承链梳理清楚,这是理解问题的基础:
A是最顶层基类,自带成员m = 5005B普通继承(非虚拟)自AC虚拟继承自BD虚拟继承自B,同时自己额外定义了成员m = 6006E多继承自C和D
这里的关键是:C 和 D 都用了虚拟继承 B,所以在 E 的对象中,只会存在一个 B 的实例——这正是虚拟继承的核心作用,用来解决多继承中“菱形继承”导致的基类实例重复问题。
逐个分析输出内容
1. e.A::m = 5005
B 是普通继承 A,所以那个唯一的 B 实例里包含了一个 A 的实例,A::m 的初始值就是5005。你通过e.A::m明确指定了要访问 A 类的成员,所以直接取到这个初始值,完全不受其他类中同名m的影响。
2. e.D::m = 6006
D 类自己定义了成员 m,这个m和A里的m是完全独立的两个成员(只是名字相同而已)。e.D::m明确指定访问D类的m,所以取到的是D中初始化的6006——哪怕你后面给e.m赋值了303,也不会改变D子对象里的这个m值,因为你赋值的是E对象最终解析的m,不是D内部的存储值。
3. e.m = 303
这是最容易困惑的点,当你直接写e.m时,编译器会遵循名字查找优先级来确定访问哪个m:
C继承自B,B又继承自A,所以C的作用域里能看到A::m,但C自己没定义新的mD自己定义了m,根据C++的名字隐藏规则,这个m会把从B继承来的A::m给隐藏掉E同时继承C和D,此时C带来的A::m和D带来的D::m中,编译器会优先选择自身定义了成员的基类版本(也就是D::m),因为它的优先级更高(自己定义的比继承来的更“具体”)
所以e.m实际上绑定的是D类的m成员,你给它赋值303后,输出自然就是303了。
额外小补充
如果想直接访问A::m而不写A::限定符,你可以用e.B::m或者e.C::m,因为B和C都继承了A的m,而且没有自己定义同名成员,所以它们的m就是A::m。
内容的提问来源于stack exchange,提问作者NewOasis
相关产品推荐
相关产品推荐

