对于我正在编写的应用程序,一个重要的部分是用户可以为不同的进程选择任何可用选项。所有这些选项都派生自同一个基类。不过,我确实偶尔会添加新选项,而且我想让这个过程尽可能简单。所以,在浏览了网络和 SO 之后,这就是我所拥有的:
基类:
class Base {
double some_member;
virtual double some_method() = 0;
};
派生类:
class Derived : Base {
//...
};
保存可用类型表并根据指定名称创建派生类的工厂:
template <typename B>
class Factory{
public:
template <typename D>
void registerType(std::string name)
{
static_assert(std::is_base_of<B, D>::value, "class doesn't derive from the base");
table_[name] = &createFunc<D>;
}
B* create(std::string name)
{
const auto it = table_.find(name);
if(it != table_.end())
return it->second();
FILE_LOG(logERROR) << "unidentified option, acceptable options are:";
for(auto const &m : list())
FILE_LOG(logERROR) << '\t' << m;
return nullptr;
}
std::vector<std::string> list()
{
std::vector<std::string> lst;
for(auto const &iter : table_)
lst.push_back(iter.first);
return lst;
}
private:
template<typename D>
static B* createFunc()
{
return new D();
}
typedef B* (*PCreateFunc)();
std::map<std::string, PCreateFunc> table_;
};
包含特定进程的所有选项的类:
class OptsContainer {
private:
std::vector<std::unique_ptr<Base>> opts_;
public:
//some other stuff
void addOption(const std::string &); //adds a new option with given name
static Factory<Base> factory;
};
Factory<Base> OptsContainer::factory;
void OptsContainer::addOption(const std::string &name)
{
opts_.push_back(std::unique_ptr<Base>(factory.create(name)));
}
此时,每当我添加一个新的派生类时,我只需要在工厂表中注册该类:
///All older includes
#include "derived42.h"
void initOptions()
{
//all other registrations
OptsContainer::factory.registerType<Derived42>("Derived42");
}
我在程序的最开始调用了 initOptions
。这很好用,但我觉得应该可以让它变得更好。我想要的是只需要添加 #include "derived42"
和注册自己的类型,因此不需要 initOptions
函数并在一开始就调用它。
我是否必须使用 Boost/Loki/...(如另一篇文章所述)?这在 Vanilla C++ 中甚至可能吗?还是我应该只接受我现在拥有的东西?仅供引用,我正在使用 Visual Studio Express 2015 编写我的程序,但我也可以将代码移至 Linux (gcc)。换句话说,不喜欢使用 VS2015 中未实现的 c++11/c++14 模式,但如果需要,我可以轻松地将所有内容移动到 gcc。
最佳答案
我觉得你的代码太复杂了。也许我怀念是有原因的。
您无法避免注册。您正在寻找的是在编译时注册,我认为这是不可能的。既然你是在编译期找注册,那就意味着你不需要在接口(interface)中暴露注册方法。因此,您的客户端接口(interface)应该由基类和创建方法组成:
// { client interface header
class B
{
public:
virtual ~B() = 0 {}
//...
};
B* Create( const char* s );
// } client interface header
一个简单的创建函数:
// { client interface implementation
template< typename T >
B* New()
{
return new T;
}
typedef B* (*PFNew)();
B* Create( const char* s )
{
typedef std::map< string, PFNew > Map;
static Map m;
if ( ! m.size() )
{
m[ D1::Signature() ] = New< D1 >;
m[ D2::Signature() ] = New< D2 >;
//...
}
Map::const_iterator ci = m.find( s );
if ( ci == m.end() )
throw -1;
return ci->second();
}
// } client interface implementation
关于c++ - 在工厂模式中自动注册派生类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34092685/