我有一个非常简单的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
,这显然是我想要避免的。怎么办呢?
答案 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 */ }},
};