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
相关产品推荐
相关产品推荐

