使用CRTP模式时,工厂方法返回的变量类型X应如何声明?
问题分析与解决方案
现有代码的核心错误
- 你当前使用的CRTP基类
ConfigManager<T>是模板类,ConfigManager<RedisConfiguration>和ConfigManager<FileConfiguration>是完全独立、无继承关系的两个类型,无法用同一个编译期确定的静态类型接收运行时动态生成的不同实例。 - 你写的工厂方法
CreateConfigManager定义为模板函数,模板参数TConfigurationStore需要在编译期确定,但方法内部是根据运行时读取的INI配置选择返回的实例类型,逻辑矛盾,代码本身无法通过编译。
修复步骤
1. 新增公共非模板抽象基类
首先定义一个纯虚接口类作为所有配置类的公共基类,抽离公共方法:
class IConfigManager { public: virtual ~IConfigManager() = default; virtual bool Configure(const INIReader& iniReader) = 0; };
2. 修改CRTP基类继承公共抽象基类
让原有的CRTP模板基类继承刚才定义的抽象接口:
template <typename TConfigurationStore> class ConfigManager : public IConfigManager { public: ConfigManager() = default; bool Configure(const INIReader& iniReader) override { LOG(INFO) << "ConfigManager::Configure called."; return static_cast<TConfigurationStore*>(this)->Configure(iniReader); } };
3. 修改工厂方法实现
去掉工厂方法的模板声明,直接返回公共基类指针:
class ConfigManagerFactory { public: static IConfigManager *CreateConfigManager(const INIReader& iniReader) { std::string remoteConfigType = iniReader.Get("RemoteConfiguration", "type", ""); if (remoteConfigType == REDIS_TYPE_NAME) { return new RedisConfiguration(); } return new FileConfiguration(); } private: inline static const std::string REDIS_TYPE_NAME {"redis"}; };
4. main函数变量声明
此时main方法中X的位置直接填公共基类指针即可,更推荐使用智能指针避免内存泄漏:
int main() { // 原始指针写法,用完需要手动delete IConfigManager* myconfmgr = ConfigManagerFactory::CreateConfigManager(iniReader); // 更推荐的智能指针写法,自动管理内存 // std::unique_ptr<IConfigManager> myconfmgr = ConfigManagerFactory::CreateConfigManager(iniReader); // 正常调用方法即可 myconfmgr->Configure(iniReader); // 原始指针需要手动释放 delete myconfmgr; }
内容的提问来源于stack exchange,提问作者user1658476
相关产品推荐
相关产品推荐

