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

C++反菱形模式下实现数据实例共享的可行方案问询

问题:让TableDerived的data基类部分与TableBase的data指向同一物理实例

类的转换(构造函数)关系:

DataBase   ---->  DataDerived

        |                  |
        V                  V

    TableBase  ---->  TableDerived

每个Table类都拥有一个data属性。

问题描述

当obj为TableDerived类型时,如何让obj.data::DataBase与obj.TableBase::data指向完全相同的物理实例?

当前实现代码

struct DataBase{
    int i{};
};

struct DataDerived : DataBase{
    int j{};
    DataDerived(DataBase&& d):DataBase(std::move(d)){}
};

// 以上代码逻辑清晰,以下代码存在疑问

struct TableBase{
    DataBase data; // 不得存储在堆上!!
};

struct TableDerived: TableBase{
    DataDerived data;
};

限制条件

  • 不希望Table类继承自Data类;
  • 不使用动态内存分配;
  • 要求四个类均可独立完整存在(非聚合类型,仅包含属性)。

已尝试方案

  • 使用shared_ptr会引入动态内存分配,不符合需求;
  • 虚继承要求Table类继承自Data类,不符合既定继承关系定义。

解决方案

核心思路是通过union内存重叠,让TableDerived中DataDerived的DataBase基类子对象与TableBase的data共享同一内存空间,同时满足所有限制条件:

#include <utility>

struct DataBase{
    int i{};
};

struct DataDerived : DataBase{
    int j{};
    DataDerived(DataBase&& d):DataBase(std::move(d)){}
    // 保留独立构造能力
    DataDerived() = default;
};

struct TableBase{
    DataBase data;
    // 保留独立构造能力
    TableBase() = default;
    TableBase(DataBase db) : data(std::move(db)) {}
};

struct TableDerived {
    // union让TableBase与DataDerived共享前sizeof(DataBase)的内存
    union {
        TableBase base;
        DataDerived data;
    };

    // 构造函数:先初始化TableBase的data,再复用该内存构造DataDerived
    TableDerived(DataBase db) {
        // 初始化TableBase的data成员
        new (&base.data) DataBase(std::move(db));
        // 在base的内存位置构造DataDerived,复用已初始化的DataBase
        new (&data) DataDerived(std::move(base.data));
    }

    // 保留独立构造能力
    TableDerived() {
        // 默认构造DataDerived,同时初始化其基类DataBase(即base.data)
        new (&data) DataDerived();
    }

    // 手动调用析构函数,union成员不会自动析构
    ~TableDerived() {
        data.~DataDerived();
    }

    // 禁用拷贝/移动构造避免内存管理问题(可按需实现)
    TableDerived(const TableDerived&) = delete;
    TableDerived& operator=(const TableDerived&) = delete;
    TableDerived(TableDerived&&) = delete;
    TableDerived& operator=(TableDerived&&) = delete;
};

方案说明

  1. 内存重叠实现:union确保TableBase::data与DataDerived的DataBase基类子对象占用同一内存地址,完全满足“同一物理实例”的要求;
  2. 无动态内存分配:所有对象均分配在栈或对象自身内存中,符合限制条件;
  3. 类的独立性:四个类都保留默认构造能力,可单独实例化使用;
  4. 构造安全:通过placement new手动控制对象构造顺序,确保DataDerived正确复用TableBase的DataBase实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 23:25:37