反射机制:程序能够控制和调整自己的行为。对于我们最常见的反射机制就是通过输入获取对应的实例。
举个例子我们有两个类:
clas A:public Base {
public:
A(){};
};
class B:public Base {
public:
B(){};
};
我们输入 A 的时候要能够得到一个A的实例。办法有很多在此例子中你甚至可以用switch case来实现。
但是我们最长见的手段就是用一个map进行类实例的存储:
std::map<std::string, Base*> instanceMap;
在程序初始化的时候建立好instanceMap 然后在用的时候进行instanceMap.find("A") 来获取对应实例。
如果有这种情况就是:instanceMap需要在主程序执行前就初始化好,而且初始化的工作不能进行集中,也就是说
不能通过循环方式将各个类实例插入该map,因为类太多,而且类的增长很快这段代码会相对难以维护。
于是我们就想到一个办法就是在类源文件的类定义最后加一个宏来进行类实例的注册。这样类的开发者只需要少量的工作就能
实现自己新编写的类的注册工作。而且注册工作会在主函数执行前完成。
宏可以如下方式:
class C:public base {
public:
C(){}
};
REGISTRY_CLASS(C);
这样C类就注册好了。那这个宏怎么写呢?我们知道我们不能直接执行 instanceMap["C']=new C();
操作逻辑必须放在函数,以及调用该函数的方式执行。一个解决办法就是通过声明一个类变量,类变量的构造函数调用我们想执行的代码。
比如:
class registry_C {
public:
registry_C(){
instanceMap["C"] = new C();
}
};
registry_C registry_c_inst;
当然这个注册函数得用宏实现:
#define REGISTRY_CLASS(class_name) \
class registry_##class_name { \
public: \
registry_##class_name() { \
instanceMap[#class_name] = new class_name(); \
} \
}; registry_##class_name registry_##class_name##inst;
这样一个简单的注册宏就定义好了,以后在每个类实现后调用注册宏就能完成宏的注册。
当然有时候我们需要通过类名获取的是一个类的新实例,这是我们map存储的就不是类实例了,而是一个类构造函数,或者
类的生成函数。
方法一样:
typedefine Base* (*getBase) ();
map<string, getBase> generatorMap;
宏我们可以这样定义:
线定义生成函数 的生成宏:
#define CREATE_GENERATOR(class_name) \
static Base* gen_##class_name () { \
return new class_name(); \
}\
#define REGISTRY_CLASS_GENERATOR(class_name) \
CREATE_GENERATOR(class_name); \
generatorMap[#class_name] = &gen_##class_name;
使用的时候:
Base* inst = (generatorMap["C"])(); 即可。当然一些错误判断就不写了。