根据值实例化不同对象类型的最佳方法?

时间:2013-05-13 08:50:32

标签: c++

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

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;

1 个答案:

答案 0 :(得分:2)

很大程度上取决于具体情况,但最常见 解决方案可能是使用地图的静态实例来实现 工厂功能。如果地图的键类型很小 整数值,如您的示例中所示,“map”仅此而已 而不是C风格的数组:

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

更一般地说,你可以使用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))();
}

我已经创建了函数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)();
}

你会注意到静态如何简化声明(和 函数调用指针 - 指针指向 成员函数已成为函数的简单指针。