子类查找表

时间:2014-06-05 15:01:53

标签: c++ function-pointers initializer-list

我有一个非常简单的C ++查找表用于调度命令:

template <class T> Action* CreateAction(Command *c)
{
    return new T(c);
}

typedef Action* CreateActionFunc(Command *c);

typedef struct ActionTable {
    string name;
    CreateActionFunc *func;
} ActionTableEntry;

vector<ActionTableEntry> GlobalActionTable = {

    { "quit"      , &CreateAction<DoQuit> },
};

这很好用,但我宁愿让我的CreateAction函数在堆栈上构造新对象并按值返回。但是当我写这篇文章时:

template <class T> T CreateAction(Command *c)
{
    return T(c);
}

typedef Action CreateActionFunc(Command *c);

然后程序将不再编译。首先,我得到一个错误,即抽象类无法实例化(在typedef行上),还有一个错误,即表的初始化列表与向量的类型不匹配。

有一个非常相似的问题here,但每个答案在工厂方法中使用new,这显然是我想要避免的。怎么办呢?

3 个答案:

答案 0 :(得分:1)

Action子类比Action类本身有更多的信息 - 指向它的成员函数,数据成员等的表。如果按值返回,那么没有足够的内存来保存这些信息。会发生一些称为切片的事情。

This回答更好地解释了。


如何做这样的事情:

class Action {
    void do_something(Command& params) = 0;
};
class SayHello {
    void do_something(Command& params) { std::cout << "Hi!" << std::endl; }
}
class SayBye {
    void do_something(Command& params) { std::cout << "Goodbye." << std::endl; }
}

.....

SayHello hello;
SayBye   bye;
Quit     quit;
std::map<string, Action&> action_table = {
    {"hello", hello},
    {"bye", bye},
    {"quit", quit},
};

....

Action& getAction(Command* command) {
   ...;
   return action_from_map;
}

这会创建一次动作,并通过引用返回它们。

答案 1 :(得分:1)

您不能按值使用对象的多态性。 需要指点或参考。 我猜你在这里有一个Action接口(所以是一个抽象类),所以你不能创建这种动态类型的对象。您所能做的就是发送一个Action类型的指针,其动态类型为派生类(所以我假设你已经在做什么)。 您可以在堆栈上创建派生类型的值对象并返回Base类的引用并仍然使用多态,但是您需要解决Derived对象问题的生命周期。

答案 2 :(得分:1)

这样简单的事情怎么样?

std::map<string, std::function<void(CommandArgs const&)>> action_table = 
{
    {"hello", [](CommandArgs const& args) { /* do something */ }},
};