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

C++如何让Module派生类仅能通过基类工厂方法实例化

实现方案

核心逻辑是限制子模块构造函数的访问权限,仅允许基类Module的addSubModule方法调用构造逻辑,有两种常用的实现方案:

方案1:密钥(Passkey)惯用法(更推荐)

该方案侵入性低,不需要每个子模块声明友元,也能保留std::make_shared的使用:

修改后的完整代码

#include <memory>
#include <vector>
#include <utility>

class Module
{
    // 私有密钥结构体,仅Module内部可创建其实例
    struct ConstructorPasskey {};
public:
    template<typename T, typename... Args>
    std::shared_ptr<T> addSubModule(Args&&... args)
    {
        // 内部传入密钥构造子模块
        std::shared_ptr<T> module = std::make_shared<T>(ConstructorPasskey{}, std::forward<Args>(args)...);

        children.emplace_back(module);
        module->parent = this;

        return module;
    }

protected:
    Module() = default;
    Module* parent = this;
    std::vector<std::shared_ptr<Module>> children;
};

class SomeSubModule : public Module
{
public:
    // 构造函数第一个参数必须是Module的私有密钥,外部无法获取
    SomeSubModule(Module::ConstructorPasskey /* 无需参数名,仅做权限校验 */, int param1, int param2)
    {
        // 原有初始化逻辑保持不变
    }
};

void Usage()
{
    Module rootModule;

    rootModule.addSubModule<SomeSubModule>(1, 2);   // ✅ 合法调用,内部自动传入密钥
    // SomeSubModule sub(1, 2);                     // ❌ 编译报错:无匹配的构造函数
    // SomeSubModule sub(Module::ConstructorPasskey{}, 1, 2); // ❌ 编译报错:ConstructorPasskey是Module私有成员,外部不可访问
}

方案优势

  • 仅需要在子模块构造函数加一个固定前置参数,无需额外声明
  • 权限控制严格,完全杜绝外部直接构造的可能
  • 可以正常使用std::make_shared,内存安全更有保障

方案2:友元声明方案

如果不想修改子模块的构造函数参数列表,可以用友元授予addSubModule访问私有构造的权限:

修改要点

  • 所有子模块的构造函数改为私有
  • 每个子模块内声明Module::addSubModule为友元
  • 调整addSubModule的实现,避免std::make_shared无法访问私有构造的问题

关键代码示例

// Module类的addSubModule修改为直接new构造
template<typename T, typename... Args>
std::shared_ptr<T> addSubModule(Args&&... args)
{
    std::shared_ptr<T> module = std::shared_ptr<T>(new T(std::forward<Args>(args)...));
    children.emplace_back(module);
    module->parent = this;
    return module;
}

// 子模块修改
class SomeSubModule : public Module
{
    // 声明addSubModule模板为友元,允许其访问私有构造函数
    template<typename T, typename... Args>
    friend std::shared_ptr<T> Module::addSubModule(Args&&... args);
private:
    SomeSubModule(int param1, int param2)
    {
        // 原有初始化逻辑不变
    }
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 12:48:04