未赋值的ob.derived2::i编译后值为33且总和88,求技术解释
嘿,这个问题其实涉及两个关键知识点:C++里未初始化成员的未定义行为,还有菱形继承带来的重复基类实例。让我给你一步步拆解清楚:
1. 菱形继承导致的双重基类实例
你的代码里是典型的菱形继承结构:
base作为基类,derived1和derived2都公开继承自它derived3又同时继承了derived1和derived2
这种情况下,derived3的对象里会包含两个完全独立的base子对象:一个来自derived1分支,另一个来自derived2分支。所以你代码里的ob.derived1::i和ob.derived2::i是两个不同的变量,存在内存的不同位置。
你只给ob.derived1::i赋值了10,但ob.derived2::i自始至终都没被初始化过。
2. 未初始化变量的“垃圾值”本质
在C++中,像main函数里的derived3 ob这种局部对象,它的非静态成员如果没有被显式赋值,其值属于未定义行为——说白了就是这块内存之前用过,残留了一些旧数据(栈内存里的垃圾),程序直接把这些旧数据当成了变量的值。
你看到的33就是这么来的,换个机器运行、或者调整代码里的变量顺序,这个值大概率会变成别的数字,完全是随机的。
3. 关于总和的计算
你代码里的sum = ob.derived2::i + ob.j + ob.k,其中j=20、k=30,加上随机的33的话,结果应该是83?可能你笔误写成了88?不过不管怎样,核心问题还是未初始化的derived2::i取到了栈上的垃圾值。
如果你希望整个继承体系里只存在一个base实例(让derived1和derived2共享同一个base子对象),可以用虚继承来解决:
// 修改derived1和derived2的继承方式 class derived1 : virtual public base { public: int j; }; class derived2 : virtual public base { public: int k; };
这样derived3里就只有一个base子对象,你直接赋值ob.i=10就行,不会再出现两个独立的i,也能避免忘记初始化其中一个的问题。
另外,最好养成初始化所有成员变量的习惯,比如给base添加构造函数,或者在声明成员时直接赋默认值,从根源上避免未定义行为带来的随机值问题。
内容的提问来源于stack exchange,提问作者jonybekov

