【发布时间】:2021-09-01 15:33:55
【问题描述】:
当使用 CRTP 时,我试图根据一些配置值创建对象。 但是我不确定调用Factory create方法时我在main方法中声明的类型应该是什么。
这是 CRTP 的基类
template <typename TConfigurationStore>
class ConfigManager
{
public:
ConfigManager() = default;
bool Configure(const INIReader& iniReader)
{
LOG(INFO) << "ConfigManager::Configure called.";
return static_cast<TConfigurationStore*>(this)->Configure(iniReader);
}
};
我们想使用的实现。
class RedisConfiguration : public ConfigManager<RedisConfiguration>
{
public:
bool Configure(const INIReader& iniReader)
{
LOG(INFO) << "RedisConfiguration::Configure called";
return true;
}
};
另一个实现...
class FileConfiguration : public ConfigManager<FileConfiguration>
{
public:
bool Configure(const INIReader& iniReader)
{
LOG(INFO) << "EmptyConfiguration::Configure called";
return false;
}
};
class ConfigManagerFactory
{
public:
template <typename TConfigurationStore>
static ConfigManager<TConfigurationStore> *CreateConfigManager(const INIReader& iniReader)
{
std::string remoteConfigType = iniReader.Get("RemoteConfiguration", "type", "");
if (remoteConfigType == REDIS_TYPE_NAME)
{
return new RedisConfiguration();
}
return new EmptyConfiguration();;
}
private:
inline static const std::string REDIS_TYPE_NAME {"redis"};
};
我的问题是我应该用什么代替 X
int main()
{
X myconfmgr = ConfigManagerFactory::CreateConfigManager(iniReader);
}
【问题讨论】:
-
为什么不使用
auto? -
我需要在另一个实际使用这个对象的类的构造函数中传递这个 myconfmgr。我应该在另一个类的构造函数中使用什么类型。
-
我假设这是因为它是一个精简的示例,但这对于 CRTP 模式甚至没有意义。派生类的
Configure函数会影响 CRTP 基类的Configure——所以你永远不会调用基类,除非你只持有基类对它的引用(此时,缺少virtual析构函数如果被基删除,将正式成为UB) -
@Human-Compiler 所以在这种情况下我无法使用 CRTP 吗?而动态多态性将是虚拟方法的唯一解决方案?
-
我的意思是这取决于您还希望完成什么; CRTP 仍然有帮助。但是,当前的代码 sn-ps 看起来是在尝试避免
virtual函数,同时仍然创建多态行为——这可能不像您期望的那样工作。如果您调用像ConfigManager<T>这样没有virtual析构函数的基类的析构函数(例如通过delete基类),那么它是未定义的行为——即使派生类没有成员。它可能工作,但依赖它并不安全。