我正在重构一个 C++ 应用程序以更好地利用多态性。我有一个大型工厂方法,它基于枚举实例化正确的对象。除了有一个大的 switch 语句之外,有没有办法让一个查找表从 Enum 的值映射到我可以用来创建正确对象的类?
问问题
202 次
3 回答
4
是的,使用地图:
struct Base { virtual ~Base(); };
struct Factory
{
enum Types { ThingA, WidgetB, GadgetC };
typedef Base * (*MakerFunction)();
static std::map<Types, MakerFunction> makers;
static std::unique_ptr<Base> create(Types t)
{
return { makers[t]() };
}
};
现在,对于从您派生的每个对象,Base
只需将合适的创建函数插入到地图Factory::makers
中。
例子:
struct Thing : Base
{
static Base * create() { return new Thing; }
};
// somewhere
Factory::makers[Factory::ThingA] = &Thing::create;
(就个人而言,我可能会unique_ptr
在所有接口中使用 s ,并且可能有某种自注册机制和辅助类,该类在构造函数中进行注册。您还想添加检查枚举值实际上是在地图中。您也可以使用这种方法进行字符串键控类选择。)
于 2013-09-06T20:58:42.913 回答
1
你不能有一个从枚举到类的映射,但你可以有一个到工厂函数的映射。就像是
typedef BaseClass* (*Maker_t)();
template <typename T>
BaseClass* Maker() { return new T(); }
std::map<MyEnum, Maker_t> makers = {{CLASS_A, Maker<ClassA>}, ...};
BaseClass* b = makers[enumValue]();
于 2013-09-06T20:59:09.353 回答
1
当然。给自己写一个模板工厂函数,例如:
enum EnumType {
Derived1,
Derived2,
...
};
template <class T>
MyBase* CreateSomething() {
return new T();
}
然后像这样声明一个查找表:
typedef MyBase*(*factory_t)();
factory_t factories[] = {
&CreateSomething<Derived1>,
&CreateSomething<Derived2>,
...
}
并像这样调用:
EnumType my_val = ...;
MyBase* b = factories[my_val]();
为了安全起见,我建议使用 unique_ptr 而不是原始指针,我只使用上面的原始指针来保持示例简单。std::array 或 std::vector 而不是数组也是如此。
如果您的枚举值是备用的,则 std::map 可能更合适,但使用普通枚举(连续,从零开始)是不必要的开销。
于 2013-09-06T21:05:33.937 回答