C++菱形继承问题:子类如何分别继承不同父类的属性值?
C++菱形继承:自由选择父类属性值的解决方案
问题描述
在菱形继承场景下:
- 基类A的带参构造函数初始化
_hp=10、_ep=10、_ad=0 - 类B、C均虚继承A,B构造函数将
_hp设为100、_ep设为50、_ad设为20;C构造函数将_hp设为100、_ep设为100、_ad设为30 - 类D同时继承B和C,期望D继承B的
_ep(50)、C的_hp(100)和_ad(30),但实际输出中_ep始终为100(来自C),结果受D的继承顺序影响,需要实现自由访问任意父类属性值的效果。
最小可复现代码
#include <iostream> #include <string> class A { public : A(){ return ; }; A(std::string name) : _hp(10), _ep(10), _ad(0){ std::cout << "A object created !" << std::endl; return ; }; ~A(){ std::cout << "A object " << this->_name << " destroyed." << std::endl; return ; }; protected: std::string _name; int _hp; int _ep; int _ad; }; class B : virtual public A { public : B(){ return ; }; B(std::string name) : A(name){ std::cout << "B object created !" << std::endl; this->_hp = 100; this->_ep = 50; this->_ad = 20; return ; }; ~B(){ std::cout << "B object " << this->_name << " destroyed." << std::endl; return ; }; }; class C : virtual public A { public : C(){ return ; }; C(std::string name) : A(name){ std::cout << "C object created !" << std::endl; this->_hp = 100; this->_ep = 100; this->_ad = 30; return ; }; ~C(){ std::cout << "C object " << this->_name << " destroyed." << std::endl; return ; }; }; class D : public B, public C { public : D(){ return ; }; D(std::string name) : A(name + "_comes_from_a"){ this->_name = name; std::cout << "D object created !" << std::endl; this->_hp = C::_hp; this->_ep = B::_ep; this->_ad = C::_ad; std::cout << "HIT POINTS " << this->_hp << std::endl; std::cout << "ENERGY POINTS " << this->_ep << std::endl; std::cout << "ATTACK DAMAGE " << this->_ad << std::endl; return; } ~D(){ std::cout << "D object " << this->_name << " destroyed." << std::endl; return ; }; }; int main(void) { D obj_D("TEST"); return (0); }
问题根源
虚继承机制下,基类A的实例在D对象中仅存在一份。构造顺序为A → B → C → D:B构造时修改了A的_ep为50,但后续C构造时又将_ep覆盖为100。因此D中尝试访问B::_ep时,实际指向的是被C修改后的共享A成员,而非B最初设置的50。
解决方案
方案1:为B、C新增独立成员存储自身属性值
让B和C各自保存自己的目标属性值,而非直接修改共享的基类成员,这样D可以直接访问这些独立变量,不受构造顺序影响:
修改B和C的定义:
class B : virtual public A { public: B() {}; B(std::string name) : A(name), _b_hp(100), _b_ep(50), _b_ad(20) { std::cout << "B object created !" << std::endl; }; ~B(){ std::cout << "B object " << this->_name << " destroyed." << std::endl; }; protected: int _b_hp; int _b_ep; int _b_ad; }; class C : virtual public A { public: C() {}; C(std::string name) : A(name), _c_hp(100), _c_ep(100), _c_ad(30) { std::cout << "C object created !" << std::endl; }; ~C(){ std::cout << "C object " << this->_name << " destroyed." << std::endl; }; protected: int _c_hp; int _c_ep; int _c_ad; };
调整D的构造函数:
D(std::string name) : A(name + "_comes_from_a"), B(name), C(name) { this->_name = name; std::cout << "D object created !" << std::endl; this->_hp = C::_c_hp; this->_ep = B::_b_ep; this->_ad = C::_c_ad; std::cout << "HIT POINTS " << this->_hp << std::endl; std::cout << "ENERGY POINTS " << this->_ep << std::endl; std::cout << "ATTACK DAMAGE " << this->_ad << std::endl; }
方案2:在D中直接显式设置目标值
如果明确知道每个属性的期望数值,可跳过父类的属性覆盖逻辑,在D构造函数中直接设置最终值:
D(std::string name) : A(name + "_comes_from_a"), B(name), C(name) { this->_name = name; std::cout << "D object created !" << std::endl; // 直接设置目标属性值 this->_hp = 100; this->_ep = 50; this->_ad = 30; std::cout << "HIT POINTS " << this->_hp << std::endl; std::cout << "ENERGY POINTS " << this->_ep << std::endl; std::cout << "ATTACK DAMAGE " << this->_ad << std::endl; }
方案3:在D构造函数中覆盖父类的修改结果
利用构造顺序的特性,在D构造阶段重新设置被C覆盖的_ep值,确保最终结果符合预期:
D(std::string name) : A(name + "_comes_from_a"), B(name), C(name) { this->_name = name; std::cout << "D object created !" << std::endl; // 覆盖C设置的_ep值 this->_ep = 50; this->_hp = 100; this->_ad = 30; std::cout << "HIT POINTS " << this->_hp << std::endl; std::cout << "ENERGY POINTS " << this->_ep << std::endl; std::cout << "ATTACK DAMAGE " << this->_ad << std::endl; }
内容的提问来源于stack exchange,提问作者Mitsun0bu
相关产品推荐
相关产品推荐

