C++中存储B实例或含B实例的C实例引用的方案咨询
可行的实现方案
1. 使用std::variant(C++17及以上)
这是最直接的惯用方案,利用标准库的变体类型存储两种可能的对象引用(避免值拷贝),再通过统一逻辑提取底层的B*。
示例代码:
#include <variant> #include <functional> // 目标存储类 struct D { // 存储B或C的引用,用std::reference_wrapper避免拷贝对象 std::variant<std::reference_wrapper<B>, std::reference_wrapper<C>> target; // 统一获取底层B指针 B* get_b() { return std::visit([](auto& val) -> B* { using T = std::decay_t<decltype(val.get())>; if constexpr (std::is_same_v<T, B>) { return &val.get(); } else if constexpr (std::is_same_v<T, C>) { // 若需确保C的object指向B,可添加断言 return static_cast<B*>(val.get().object); } return nullptr; }, target); } }; // 使用示例 B b_inst; C c_inst; c_inst.object = &b_inst; D d1; d1.target = std::ref(b_inst); D d2; d2.target = std::ref(c_inst); B* b_ptr1 = d1.get_b(); // 指向b_inst B* b_ptr2 = d2.get_b(); // 指向c_inst中的b_inst
2. 自定义类型擦除接口
如果需要兼容C++17之前的版本,或者需要更灵活的扩展,可以抽象统一接口,为B和C分别实现适配器类。
示例代码:
#include <memory> // 抽象访问接口,定义获取底层对象的行为 struct TargetAccessor { virtual ~TargetAccessor() = default; virtual B* get_b() = 0; }; // B的适配器 struct BAccessor : TargetAccessor { B& b_obj; BAccessor(B& obj) : b_obj(obj) {} B* get_b() override { return &b_obj; } }; // C的适配器 struct CAccessor : TargetAccessor { C& c_obj; CAccessor(C& obj) : c_obj(obj) {} B* get_b() override { return static_cast<B*>(c_obj.object); } }; // 目标存储类 struct D { std::unique_ptr<TargetAccessor> accessor; // 支持直接传入B或C实例 D(B& b) : accessor(std::make_unique<BAccessor>(b)) {} D(C& c) : accessor(std::make_unique<CAccessor>(c)) {} B* get_b() { return accessor->get_b(); } };
3. 重新设计类结构的思路
如果上述方案不符合需求,可以考虑调整原有结构:
- 把C中与
object相关的逻辑抽离为独立组件,让B和该组件组合,而非让C持有A*; - 定义非侵入式 trait 模板,为B和C分别实现获取底层对象的逻辑,通过模板统一调用(类似标准库
std::begin的模式)。
trait方式示例:
// 定义trait模板,默认无实现 template<typename T> struct TargetTrait; // 为B特化trait template<> struct TargetTrait<B> { static B* get(B& obj) { return &obj; } }; // 为C特化trait template<> struct TargetTrait<C> { static B* get(C& obj) { return static_cast<B*>(obj.object); } }; // 模板化的目标存储类 template<typename T> struct D { T& target; B* get_b() { return TargetTrait<T>::get(target); } }; // 使用示例 B b_inst; C c_inst; c_inst.object = &b_inst; D<B> d1{b_inst}; D<C> d2{c_inst};
这种方式更轻量,但D会是模板类,若需要统一的非模板类型,前两种方案更合适。
内容的提问来源于stack exchange,提问作者ERSUCC
相关产品推荐
相关产品推荐

