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

C++如何定义可外部传入或内部构造的类成员变量

问题解决思路

先分析你给出的两个方案:

  • 第一个方案会默认构造m_aObj,即便外部传入了A对象,这个内部对象也完全用不上,若A的构造成本较高,会造成不必要的资源浪费,合理性不足。
  • 第二个方案用std::shared_ptr虽能编译通过,但强制引入了共享所有权的语义,而你明确不需要共享,额外的引用计数也会带来性能开销,并非最优选择。

更优方案:用std::variant存储两种状态

C++17及以上版本可借助std::variant存储两种状态:要么是对外部A对象的引用(用std::reference_wrapper包装,因为引用无法直接存入variant),要么是自身拥有的std::unique_ptr<A>。既满足两种构造场景,又无多余开销,也不会强制共享所有权。

示例代码:

#include <variant>
#include <memory>
#include <functional>

class A {
public:
    void do_something() { /* 非const方法实现 */ }
};

class B {
public:
    // 构造函数1:内部构造A,所有权归B
    B() : m_a(std::make_unique<A>()) {}

    // 构造函数2:外部传入A,所有权归调用方
    B(A& a) : m_a(std::ref(a)) {}

    void useA() {
        std::visit([](auto&& val) {
            using T = std::decay_t<decltype(val)>;
            if constexpr (std::is_same_v<T, std::reference_wrapper<A>>) {
                val.get().do_something();
            } else if constexpr (std::is_same_v<T, std::unique_ptr<A>>) {
                val->do_something();
            }
        }, m_a);
    }

private:
    std::variant<std::reference_wrapper<A>, std::unique_ptr<A>> m_a;
};

兼容旧标准方案:继承拆分两种场景

若编译器不支持C++17,可通过继承拆分B的两种场景,逻辑清晰且无需依赖新特性:

class A {
public:
    void do_something() { /* 方法实现 */ }
};

class BBase {
public:
    virtual void useA() = 0;
    virtual ~BBase() = default;
};

// 持有外部A的引用,所有权归调用方
class BExternal : public BBase {
public:
    BExternal(A& a) : m_a(a) {}
    void useA() override { m_a.do_something(); }
private:
    A& m_a;
};

// 内部构造A,所有权归自身
class BInternal : public BBase {
public:
    BInternal() : m_a() {}
    void useA() override { m_a.do_something(); }
private:
    A m_a;
};

总结

  • 你原有的两个方案弊端明显,不推荐使用。
  • 优先选择std::variant方案,简洁高效,符合现代C++风格。
  • 若无法使用C++17,继承拆分的方案是可靠替代。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 05:36:11