我在 C++ 中有一个带有几个子类的抽象类。
是否可以通过宏或模板元编程以某种方式执行以下操作:
foreach subclass of Base:
mymap[subclass::SOME_CONSTANT] = new subclass();
我在 C++ 中有一个带有几个子类的抽象类。
是否可以通过宏或模板元编程以某种方式执行以下操作:
foreach subclass of Base:
mymap[subclass::SOME_CONSTANT] = new subclass();
你不能。
显然,您想要的是 a Factory
(或者也许Abstract Factory
)。
在 C++ 中,您设置一个工厂类并注册构建器。
class FooFactory
{
public:
typedef std::function<Foo*()> Builder;
/// returns true if the registration succeeded, false otherwise
bool Register(std::string const& key, Builder const& builder) {
return map.insert(std::make_pair(key, builder)).second;
}
/// returns a pointer to a new instance of Foo (or a derived class)
/// if the key was found, 0 otherwise
Foo* Build(std::string const& key) const {
auto it = _map.find(key);
if (it == _map.end()) { return 0; } // no such key
return (it->second)();
}
private:
std::map<std::string, Builder> _map;
};
您可以创建此工厂的单例,以在库加载期间注册派生类,这对于类似插件的架构很方便:
FooFactory& GetFooFactory() { static FooFactory F; return F; }
您可以准备一个方便的构建器:
template <typename Derived>
Foo* fooBuilder() { return new Derived(); }
然后人们应该在工厂中注册他们的派生类:
static const bool registeredBar =
GetFooFactory().Register("Bar", fooBuilder<Bar>);
注意:工厂应该是一个单例并不是强制性的,尽管在这里它不是那么邪恶,因为一旦库的负载结束它就是恒定的。
注意:对于正确的插件架构,您需要使用 RAII(而不是 bool)来处理库卸载时的注销。不过这种情况要少得多。
C++ 不允许迭代类型。枚举成员的枚举也是不可能的。看到这个:
enum Color
{
red,
green,
blue=5,
yellow
};
此外,C++ 编译器独立编译编译单元。您可以想象在编译基类实现时它不知道该类有时会被继承。