3

我正在重构一个 C++ 应用程序以更好地利用多态性。我有一个大型工厂方法,它基于枚举实例化正确的对象。除了有一个大的 switch 语句之外,有没有办法让一个查找表从 Enum 的值映射到我可以用来创建正确对象的类?

4

3 回答 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 回答