C++中"classes"(非对象)的哈希表

Hash table of "classes" (not objects) in C++

本文关键字:对象 哈希表 classes C++      更新时间:2023-10-16

为了我的大学作业,我需要用C++为一种基于函数(或命令)的语言制作一个解释器。解释器必须读取输入文件,提取单词(字符串),生成命令并执行它们。所有命令都是继承自一个公共超类(例如Command)的类,该类有一个名为execute的虚拟方法。对于从输入文件中读取的每个单词,都会创建一个命令并将其存储在vector<Command>中。

因此,我正在考虑使用一个哈希表,它的键是命令(字符串)的名称,其值是某种允许我创建特定类(或允许我访问特定类的构造函数)的对象,以便轻松地为每个单词创建类,而不是使用if-else-if链。

到目前为止,我正计划使用一个名为generate的虚拟方法创建一个CommandGenerator类,该方法返回一个新的Command对象。我的命令哈希表的值将是CommandGenerator类的对象。因此,我为所有命令派生了许多其他子类,这些子类返回从Command派生的特定新对象。

但是,类似的东西已经存在了吗?或者还有什么更优雅的方法可以做到这一点吗?有什么类型的对象可以从类中提取出来表示它吗?

如果每个命令都是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打印到屏幕上。但是,如果你非常关心速度,那就做很多假设。

您面临的基本问题是:您将类的名称作为字符串,并希望创建一个具有该名称的类。正如你所提到的,这个翻译必须以某种方式手动完成。这已经在这里讨论过好几次了,比如在用工厂模式按名称实例化类中,或者在寻找更好的C++类工厂中。我在这里要做的唯一补充是:使用好的旧宏,因为它们有字符串运算符。例如:

#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 ("%sn", makeInstance ("A")->name());
printf ("%sn", makeInstance ("B")->name());
}

当然,你可以通过使用一个包含字符串和一些函数指针或生成器类指针的哈希表来让它变得更好,但想法保持不变:要添加一个新类,只需再添加一个CREATEOBJ即可。