对于我的大学作业,我需要在C ++中为基于函数(或命令)的语言编写解释器。解释器必须读取输入文件,提取单词(字符串),生成命令并执行它们。所有命令都是从公共超类(例如Command
)继承的类,它有一个名为execute
的虚方法。对于从输入文件中读取的每个单词,将创建一个命令并将其存储在vector<Command>
。
所以,我正在考虑使用哈希表,其键是命令(字符串)的名称,其值是某种对象,允许我创建一个特定的类(或者让我访问构造函数一个特定的类),轻松地为每个单词创建类,而不是使用if-else-if链。
到目前为止,我计划使用名为CommandGenerator
的虚拟方法创建一个generate
类,该方法返回一个新的Command
对象。我的命令哈希表的值将是CommandGenerator
类的对象。因此,我从所有命令派生出许多其他子类,它们返回从Command
派生的特定新对象。
但是,这样的事情是否已经存在?还是有更优雅的方式来做到这一点?是否有任何类型的对象可以从类中提取来表示它?
答案 0 :(得分:1)
如果每个命令都是Command
的子类,为什么不使用std::vector<Command*>
并将指针推送到每个子类的实例?然后,您可以迭代向量并调用虚拟execute
函数。
将类放在向量中最接近的是boost::fusion::vector
。但是不能在运行时填充,不能用于你的特定情况。
假设您可以使用C ++ 11。如果您可以将命令定义为execute
函数,则可以执行以下操作:
map<string, function<void()>> cmds = {
make_pair("print1", [](){
cout << "1" << end;
}),
make_pair("print2", [](){
cout << "2" << end;
}),
make_pair("print3", [](){
cout << "3" << end;
})
};
然后将命令放在带有:
的向量上vector<function<void()>> list;
list.push_back(cmds["print1"]);
list.push_back(cmds["print1"]);
list.push_back(cmds["print2"]);
然后用循环执行:
for (function<void()>& cmd : list)
cmd();
这应该打印112
到屏幕。但如果你非常关心速度,那就做很多ifs。
答案 1 :(得分:1)
您遇到的基本问题是:您将类的名称作为字符串,并希望创建具有该名称的类。这个翻译你必须以某种方式手动完成,就像你提到的那样。这已在此处多次讨论过,例如Instantiating classes by name with factory pattern或Looking for a better C++ class factory。我将在这里做的唯一补充:使用好的旧宏,因为它们有一个stringize-operator。 E.g:
#include <stdio.h>
#define CREATEOBJ(clss,command) if (strcmp (#clss, command)==0) return new clss;
class Base {
public:
virtual const char *name()=0;
};
class A : public Base {
public:
const char *name() {return "I am an A";}
};
class B : public Base {
public:
const char *name() {return "I am an B";}
};
Base *makeInstance (const char *nm) {
CREATEOBJ(A,nm);
CREATEOBJ(B,nm);
}
int main () {
printf ("%s\n", makeInstance ("A")->name());
printf ("%s\n", makeInstance ("B")->name());
}
当然你可以通过使用包含字符串和一些函数指针或生成器类指针的哈希表来使它更好,但是这个想法保持不变:要添加一个新类,只需添加一个CREATEOBJ-thingy