You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++菱形继承场景下如何从不同父类获取指定属性值

问题原因分析

这个问题是C++虚拟继承的固有构造规则导致的:

  • 当使用虚拟继承时,虚基类A的构造函数只由继承层级最底层的最终派生类D直接调用,所有中间父类B、C的初始化列表中对A构造函数的调用都会被完全忽略。你代码里B、C初始化列表中给A传参设置_points=20、_energy=30的逻辑,在构造D对象时根本没有执行,只有D初始化列表调用的A(name)生效,把两个属性都初始化为10。
  • 虚拟继承下整个D对象中只有一份A类子对象,B::_points、C::_energy本质上指向的都是A类的同一个成员变量,不存在B专属的_points、C专属的_energy,所以赋值时拿到的自然是A构造后的10。
解决方案

方案1:保留虚拟继承,将B、C的属性赋值逻辑移到构造函数体内

虚拟继承下B、C的构造函数体内容会正常执行,只需要把要设置的属性值写在构造函数体里即可生效:

#include <iostream>

class A
{
    protected:
        std::string _name;
        int _points;
        int _energy;
    
    public:
        A(std::string name, int points, int energy) : _name(name), _points(points), _energy(energy)
        {            
        }
        A(std::string name) : _name(name), _points(10), _energy(10)
        {
        }
};

class B : public virtual A
{
    public:
        B(std::string name): A(name, 20, 20)
        {
            // 构造函数体内设置points,构造D时该逻辑会正常执行
            _points = 20;
        }
};

class C : public virtual A
{
    public:
        C(std::string name) : A(name, 30, 30)
        {
            // 构造函数体内设置energy,构造D时该逻辑会正常执行
            _energy = 30;
        }
};

class D : public B, public C
{
    private:
            std::string _name_d;
    public:
        D(std::string name): A(name), B(name), C(name), _name_d(name)
        {
            A::_name = "another name";
            _points = B::_points;
            _energy = C::_energy;
            std::cout << "name class D   " << _name_d << std::endl;
            std::cout << "name class A   " << A::_name << std::endl;
            std::cout << "energy class D " << _energy << std::endl;
            std::cout << "points class D " << _points << std::endl;
        }
};

int main(void)
{
    D d("Bill");
    return 0;
}

修改后运行输出完全符合预期:

name class D   Bill
name class A   another name
energy class D 30
points class D 20

方案2:不使用虚拟继承,保留两份A类子对象

如果你确实需要B、C各自持有独立的A类成员,去掉继承时的virtual关键字即可,此时D对象中会存在两份独立的A类子对象,分别属于B和C,可以独立访问:

// 修改B、C的继承声明,去掉virtual
class B : public A
{
public:
    B(std::string name): A(name, 20, 20) {}
};

class C : public A
{
public:
    C(std::string name) : A(name, 30, 30) {}
};

// D构造函数访问A成员时需要明确指定父类路径
D(std::string name): B(name), C(name), _name_d(name)
{
    B::A::_name = "another name";
    _points = B::_points;
    _energy = C::_energy;
    // 其余输出逻辑不变
}

该方案的缺点是D中存在两份A子对象,会占用额外内存,访问A类成员时必须加路径前缀避免二义性,可根据实际需求选择。

内容的提问来源于stack exchange,提问作者Миля Валиева

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 03:06:03