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

C++模拟模板虚函数:简化设备类代码并保留基类抽象

简化带多态要求的设备类读写代码方案

核心思路

针对你遇到的重复switch代码、需区分读写操作、保留基类多态的需求,核心解决方向是:

  • 把位宽相关的读写逻辑抽离成通用工具,避免每个子类重复实现switch
  • 保留Device基类的虚函数接口,确保兼容std::vector<Device*>的多态容器
  • 允许子类自定义读写前的设备特定操作,不侵入通用逻辑

方案1:通用工具函数抽离

先实现一套位宽分发的通用工具,把重复的类型转换和switch逻辑集中处理:

#include <array>
#include <cstdint>
#include <type_traits>

namespace detail {
    // 通用字节转类型的加载函数
    template<typename T>
    T load_from_bytes(const uint8_t* data, uint64_t addr) {
        return *reinterpret_cast<const T*>(data + addr);
    }

    // 通用类型转字节的存储函数
    template<typename T>
    void store_to_bytes(uint8_t* data, uint64_t addr, uint64_t value) {
        *reinterpret_cast<T*>(data + addr) = static_cast<T>(value);
    }

    // 位宽到类型的映射处理器
    struct LoadHandler {
        const uint8_t* data;
        uint64_t addr;

        uint64_t operator()(std::integral_constant<size_t, 8>) const {
            return load_from_bytes<uint8_t>(data, addr);
        }
        uint64_t operator()(std::integral_constant<size_t, 16>) const {
            return load_from_bytes<uint16_t>(data, addr);
        }
        uint64_t operator()(std::integral_constant<size_t, 32>) const {
            return load_from_bytes<uint32_t>(data, addr);
        }
        uint64_t operator()(std::integral_constant<size_t, 64>) const {
            return load_from_bytes<uint64_t>(data, addr);
        }
    };

    struct StoreHandler {
        uint8_t* data;
        uint64_t addr;
        uint64_t value;

        void operator()(std::integral_constant<size_t, 8>) const {
            store_to_bytes<uint8_t>(data, addr, value);
        }
        void operator()(std::integral_constant<size_t, 16>) const {
            store_to_bytes<uint16_t>(data, addr, value);
        }
        void operator()(std::integral_constant<size_t, 32>) const {
            store_to_bytes<uint32_t>(data, addr, value);
        }
        void operator()(std::integral_constant<size_t, 64>) const {
            store_to_bytes<uint64_t>(data, addr, value);
        }
    };

    // 位宽分发入口,统一处理switch逻辑
    template<typename Handler>
    auto dispatch_by_size(uint64_t size, Handler&& handler) {
        switch(size) {
            case 8: return handler(std::integral_constant<size_t, 8>{});
            case 16: return handler(std::integral_constant<size_t, 16>{});
            case 32: return handler(std::integral_constant<size_t, 32>{});
            case 64: return handler(std::integral_constant<size_t, 64>{});
            default: 
                if constexpr(std::is_same_v<decltype(handler(std::integral_constant<size_t, 8>{})), uint64_t>)
                    return uint64_t{0};
                else
                    return;
        }
    }
}

然后修改设备类,复用通用工具:

// 基类保持原接口,补充虚析构避免内存泄漏
class Device {
protected:
    int base;
    int size;
    // 其他成员

public:
    virtual uint64_t load(uint64_t addr, uint64_t size) = 0;
    virtual void store(uint64_t addr, uint64_t value, uint64_t size) = 0;
    virtual ~Device() = default;
};

// Dram子类,简化读写实现
class Dram : public Device { // 注意:必须public继承才能支持多态
private:
    std::array<uint8_t, 1024> data;

    // 设备特定的前置操作
    void ram_specific_load() { /* 原逻辑保留 */ }
    void ram_specific_store() { /* 原逻辑保留 */ }

public:
    uint64_t load(uint64_t addr, uint64_t size) override {
        ram_specific_load();
        return detail::dispatch_by_size(size, detail::LoadHandler{data.data(), addr});
    }

    void store(uint64_t addr, uint64_t value, uint64_t size) override {
        ram_specific_store();
        detail::dispatch_by_size(size, detail::StoreHandler{data.data(), addr, value});
    }
};

方案2:CRTP辅助基类(进一步减少子类代码)

如果有多个设备子类,可使用CRTP做辅助基类,把load/store的通用逻辑统一实现,子类只需要提供数据和前置操作:

// CRTP辅助基类,继承自Device确保多态兼容性
template<typename Derived>
class DeviceHelper : public Device {
protected:
    // 让子类暴露私有数据和操作
    uint8_t* get_data() { return static_cast<Derived*>(this)->data.data(); }
    const uint8_t* get_data() const { return static_cast<Derived*>(this)->data.data(); }
    void pre_load() { static_cast<Derived*>(this)->ram_specific_load(); }
    void pre_store() { static_cast<Derived*>(this)->ram_specific_store(); }

public:
    uint64_t load(uint64_t addr, uint64_t size) override {
        pre_load();
        return detail::dispatch_by_size(size, detail::LoadHandler{get_data(), addr});
    }

    void store(uint64_t addr, uint64_t value, uint64_t size) override {
        pre_store();
        detail::dispatch_by_size(size, detail::StoreHandler{get_data(), addr, value});
    }
};

// Dram子类,仅需实现设备特定逻辑
class Dram : public DeviceHelper<Dram> {
    friend class DeviceHelper<Dram>; // 允许辅助基类访问私有成员
private:
    std::array<uint8_t, 1024> data;
    void ram_specific_load() { /* 原逻辑 */ }
    void ram_specific_store() { /* 原逻辑 */ }
};

修正后的使用代码

注意原代码中push_back(&Dram())会导致悬空指针(临时对象销毁),改用智能指针管理内存:

#include <vector>
#include <memory>

std::vector<std::unique_ptr<Device>> devices;

devices.emplace_back(std::make_unique<Dram>());
devices.emplace_back(std::make_unique<Gpu>()); // 其他设备类同理

// 原使用逻辑完全兼容
devices[1]->store(0x1234, devices[0]->load(0x4321, 64), 64);
uint32_t var = static_cast<uint32_t>(devices[1]->load(0x1212, 32));

方案优势

  1. 消除重复代码:所有位宽相关的switch和类型转换逻辑集中在detail工具中,子类无需重复实现
  2. 保留多态性:完全兼容std::vector<Device*>(或智能指针容器)的抽象管理
  3. 灵活扩展:子类可自由定义读写前的设备特定操作,不影响通用逻辑
  4. 类型安全:集中处理reinterpret_cast,避免分散的类型转换错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 15:37:05