我正在重构C ++应用程序以更好地利用多态性。我有一个大的工厂方法,基于Enum实例化适当的对象。有没有一种方法可以让一个查找表从Enum的值映射到我可以用来创建正确对象的类?
答案 0 :(得分: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
,并且可能有某种自我注册机制,辅助类在构造函数中进行注册。你也想要添加枚举值实际在地图中的检查。您也可以使用这种方法进行字符串键选择。)
答案 1 :(得分: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]();
答案 2 :(得分: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可能更合适,但是使用正常的枚举(连续,从零开始),这是不必要的开销。