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

在C++中,如何在非指针场景下访问子类拷贝到父类的属性?

问题分析与解决方案

当前代码存在对象切片问题:Super类中的data是DataSuper的实例对象,当你在Sub的构造函数中执行data = i;(i是DataSub类型)时,只会将i中属于DataSuper的部分赋值给data,DataSub特有的成员a会被直接丢弃。此时data的实际类型就是DataSuper,根本不存在a成员,这是你无法访问data.a的核心原因。

以下是无需将data设为指针的可行解决方案:

方案1:Sub类自行维护DataSub实例

让Sub类保留传入的DataSub完整实例,直接访问自己维护的对象,避免依赖被切片的继承成员:

#include <iostream>
#include <vector>
using std::vector;
using std::cout;

class DataSuper {
public:
    DataSuper() {}
};

class DataSub : public DataSuper {
public:
    int a;
    DataSub() : a(0) {} // 初始化a,避免未定义行为
};

class Super {
public:
    DataSuper data;
    Super() {}
};

class Sub : public Super {
private:
    DataSub m_data; // Sub自行维护完整的DataSub实例
public:
    Sub(DataSub i) : m_data(i) {
        data = i; // 依然会切片,但不影响m_data的完整性
    }
    
    void test() {
       cout << m_data.a << endl; // 直接访问自己维护的实例的a
    }
};

int main(int argc, char *argv[]) {
    DataSub dataSub;
    dataSub.a = 10; // 给a赋值
    Super* s = new Sub(dataSub);
    s->test(); // 输出10
    delete(s);
    return 0;
}

方案2:使用std::variant存储多态数据(C++17及以上)

利用std::variant作为data的类型,既能存储DataSuper也能存储DataSub,避免对象切片,同时无需使用原始指针:

#include <iostream>
#include <vector>
#include <variant>
using std::vector;
using std::cout;
using std::variant;
using std::get_if;

class DataSuper {
public:
    DataSuper() {}
};

class DataSub : public DataSuper {
public:
    int a;
    DataSub() : a(0) {}
};

class Super {
public:
    variant<DataSuper, DataSub> data;
    Super() {}
};

class Sub : public Super {
public:
    Sub(DataSub i) {
        data = i; // 完整存储DataSub,无切片
    }
    
    void test() {
       // 判断data是否存储的是DataSub类型
       if (auto subPtr = get_if<DataSub>(&data)) {
           cout << subPtr->a << endl;
       }
    }
};

int main(int argc, char *argv[]) {
    DataSub dataSub;
    dataSub.a = 20;
    Super* s = new Sub(dataSub);
    s->test(); // 输出20
    delete(s);
    return 0;
}

方案3:重构为模板类(类型安全的优雅设计)

将Super设计为模板类,让子类指定data的具体类型,从根源避免切片问题:

#include <iostream>
#include <vector>
using std::vector;
using std::cout;

class DataSuper {
public:
    DataSuper() {}
};

class DataSub : public DataSuper {
public:
    int a;
    DataSub() : a(0) {}
};

// 模板类,允许指定data的类型
template<typename T = DataSuper>
class Super {
public:
    T data;
    Super() {}
};

// Sub继承自Super<DataSub>,此时data就是DataSub类型
class Sub : public Super<DataSub> {
public:
    Sub(DataSub i) {
        data = i; // 无切片,直接赋值DataSub
    }
    
    void test() {
       cout << data.a << endl; // 直接访问a
    }
};

int main(int argc, char *argv[]) {
    DataSub dataSub;
    dataSub.a = 30;
    // 注意这里的指针类型需要是Sub*,或者用Super<DataSub>*
    Sub* s = new Sub(dataSub);
    s->test(); // 输出30
    delete(s);
    return 0;
}

内容的提问来源于stack exchange,提问作者Chicoscience

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 06:21:37