6

我会将数百个类的问题简化为两个,并尝试解释我的意思:

class Base {
};
class A: public Base {
};
class B: public Base{
};

static Base* foo (int bar){

    switch (bar) {
        case 0:
            return new A();
            break;              
        case 1:
            return new B();
            break;
        default:
            return new Base();
    }
}

我想根据 bar 的值来实例化对象。我只是觉得 switch-case 并不是 C++ 中为更多Base.

编辑:std::map采用我想出的方法:

struct Dictionary {
    typedef Base* (Dictionary::*FunctionPointer)(void);
    std::map <int, FunctionPointer> fmap;

    Dictionary() {
        fmap.insert(std::make_pair(0, new A()));
        fmap.insert(std::make_pair(1, new B()));
    }

    Base* Call (const int i){
        FunctionPointer fp = NULL;
        fp = fmap[i];
        if (fp){
            return (this->*fp)();
        } else {
            return new Base();
        }
    }
};

static Dictionary dictionary;
4

1 回答 1

2

很大程度上取决于具体情况,但最常见的解决方案可能是使用映射到工厂函数的静态实例。如果地图的键类型是一个小整数值,如您的示例中所示,“地图”可以只不过是一个 C 风格的数组:

static Base*
foo( int bar )
{
    static Base* (*factories[])() = [ &aFactory, &bFactory ];
    return bar >= 0 && bar < size( factories )
        ? (*factories[bar])()
        : baseFactory();
}

更一般地说,您可以使用 an std::map(区分任何可以想象的类型),并且如果不同的键应该导致相同的类型但具有不同的参数,则可以映射到工厂对象的静态实例,而不是工厂函数。

编辑:

一些改进Dictionary::Call功能的建议:

Base* Dictionary::Call( int i ) const
{
    std::map<int, FunctionPointer>::const_iterator
                        entry = fmap.find( i );
    return entry == fmap.end()
        ? new Base()
        : (this->*(entry->second))();
}

我已经创建了 function const,因为它不会修改任何东西,最重要的是,我使用std::map<>::find, 来避免在对象不存在的情况下将额外的条目插入到地图中。

由于我要添加 const,因此您必须更新 typedef:

typedef Base* (Dictionary::*FunctionPointer)() const;

另一个建议:除非工厂函数需要访问 Dictionary,否则将它们设为静态。语法要简单得多(它也可能会提高性能)。static 再次更改 typedef:

另外:在构造函数中,new A()不是构造新对象的函数在 C++11 中(在 lambda 和 之间)可能有一些东西可以促进这一点std::function,但除此之外,您仍然必须手动编写每个工厂函数。或者您可以使用模板:

template <typename Target>
Base* construct() const
{
    return new Target();
}

Dictionary()
{
    fmap.insert( std::make_pair( 0, &Dictionary::construct<A> ) );
    //  ...
}

或者,如果您将它们设为静态:

typedef Base* (*FunctionPointer)();

//  ...
template <typename Target>
static Base* construct()
{
    return new Target();
}

Base* Dictionary::Call( int i ) const
{
    std::map<int, FunctionPointer>::const_iterator
                        entry = fmap.find( i );
    return entry == fmap.end()
        ? new Base()
        : (*entry->second)();
}

您会注意到静态如何简化声明(以及通过指针的函数调用——指向成员函数的指针已成为指向函数的简单指针)。

于 2013-05-13T09:17:42.627 回答