反射:其实就是通过类的名字(类名是string)来获取类的实例。比如讲类名写在txt文件中,然后解析文本文件,拿到类名,进而那到类的实例。
在caffe中,在网络配置文件中,写入了各个层的名字,如:relu。其实,这些算子,在caffe源码里面都有对应的类实现,且类名一致,当然,caffe是通过protobuf来搞定配置文件的,配置文件的解析过程中,就会通过string的类名来拿到对应类的实例,这里,其实就是运用了反射机制。
【反射机制实现步骤】
1. 建立一个工厂类,负责存储类名与创建类实例的函数的map。
2.该工厂类提供注册函数,方便新类将其类名与类实例的创建函数放入map中。
3.该工厂类提供依据类名获取类实例的接口。
基于此,代码实现如下:
#include <iostream>
#include <string>
#include <map>
using namespace std;
//定义一个函数指针,来表示创建类的函数
typedef void * (*pFunc)();
// 定义一个工厂类
class DevFactory {
public:
static DevFactory & getInstance() {
static DevFactory cf;
return cf;
}
void * GetClassInstanceByClassName(string class_name) {
auto iter = Dev_map.find(class_name);
if (iter == Dev_map.end()) {
cout << "can not create this " << class_name << " instance" << endl;
return nullptr;
}
return iter->second();
}
void Register(string class_name,pFunc creater){
Dev_map[class_name] = creater;
}
private:
DevFactory() {}
map<string, pFunc> Dev_map;
};
class CPU {
public:
CPU() {}
void print() {
cout << "this is CPU" << endl;
}
};
void * creatCPU() {
return new CPU;
}
class GPU {
public:
GPU() {}
void print() {
cout << "this is GPU" << endl;
}
};
void * creatGPU() {
return new GPU;
}
int main(int argc, int * argv[])
{
DevFactory dev = DevFactory::getInstance();
dev.Register("CPU", creatCPU);
dev.Register("GPU",creatGPU);
CPU * cpu = (CPU *)dev.GetClassInstanceByClassName("CPU");
cpu->print();
GPU *gpu = (GPU *)dev.GetClassInstanceByClassName("GPU");
gpu->print();
system("pause");
}
结果输出如下:
【利用全局变量,实现类的自动注册】
基于事实:全局变量的初始化实在main函数运行之前完成的。
所以,我们可以完成类的自动注册,而不用在main函数内部进行手动注册。
因此,需要一个辅助类,在该来的构造函数里面,完成注册。
代码如下:
#include <iostream>
#include <string>
#include <map>
using namespace std;
//定义一个函数指针,来表示创建类的函数
typedef void * (*pFunc)();
// 定义一个工厂类
class DevFactory {
public:
static DevFactory * getInstance() {
static DevFactory *cf = new DevFactory;
return cf;
}
void * GetClassInstanceByClassName(string class_name) {
auto iter = Dev_map.find(class_name);
if (iter == Dev_map.end()) {
cout << "can not create 55 this " << class_name << " instance" << endl;
return nullptr;
}
return iter->second();
}
void Register(string class_name,pFunc creater){
cout << "register " << class_name << endl;
Dev_map[class_name] = creater;
}
private:
DevFactory() {}
map<string, pFunc> Dev_map;
};
class CPU {
public:
CPU() {}
void print() {
cout << "this is CPU" << endl;
}
};
void * creatCPU() {
return new CPU;
}
class GPU {
public:
GPU() {}
void print() {
cout << "this is GPU" << endl;
}
};
void * creatGPU() {
return new GPU;
}
class CreaterDev {
public:
CreaterDev(string class_name, pFunc creater) {
DevFactory *dev = DevFactory::getInstance();
dev->Register(class_name, creater);
}
};
CreaterDev g_dev_cpu("CPU",creatCPU); //利用全局变量的初始化,自动完成注册
CreaterDev g_dev_gpu("GPU", creatGPU);
int main(int argc, int * argv[])
{
DevFactory *dev = DevFactory::getInstance();
//dev.Register("CPU", creatCPU);
//dev.Register("GPU",creatGPU);
CPU * cpu = (CPU *)dev->GetClassInstanceByClassName("CPU"); //直接依据类名获取类的实例
cpu->print();
GPU *gpu = (GPU *)dev->GetClassInstanceByClassName("GPU");
gpu->print();
system("pause");
}
结果如下:
可以看到,利用全局变量的初始化,可以方便实现新增类的自动注册。
但是也可以看出一个问题,那就是每新增一个类,都需要新增一个create函数与一个全局变量,这些代码是完全一样的,因此,我们可以编写一个宏,来同时实现create函数的定义与全局变量的定义。
#define REGISTER(className) \
className* objectCreator##className(){ \
return new className; \
} \
CreaterDev g_creatorRegister##className( \
#className,(pFunc)objectCreator##className)
利用这个宏,来实现类的自动注册。
全部代码如下:
#include <iostream>
#include <string>
#include <map>
using namespace std;
//定义一个函数指针,来表示创建类的函数
typedef void * (*pFunc)();
// 定义一个工厂类
class DevFactory {
public:
static DevFactory * getInstance() {
static DevFactory *cf = new DevFactory;
return cf;
}
void * GetClassInstanceByClassName(string class_name) {
auto iter = Dev_map.find(class_name);
if (iter == Dev_map.end()) {
cout << "can not create 55 this " << class_name << " instance" << endl;
return nullptr;
}
return iter->second();
}
void Register(string class_name,pFunc creater){
cout << "register " << class_name << endl;
Dev_map[class_name] = creater;
}
private:
DevFactory() {}
map<string, pFunc> Dev_map;
};
class CreaterDev {
public:
CreaterDev(string class_name, pFunc creater) {
DevFactory *dev = DevFactory::getInstance();
dev->Register(class_name, creater);
}
};
#define REGISTER(className) \
className* objectCreator##className(){ \
return new className; \
} \
CreaterDev g_creatorRegister##className( \
#className,(pFunc)objectCreator##className)
class CPU {
public:
CPU() {}
void print() {
cout << "this is CPU" << endl;
}
};
REGISTER(CPU);
class GPU {
public:
GPU() {}
void print() {
cout << "this is GPU" << endl;
}
};
REGISTER(GPU);
int main(int argc, int * argv[])
{
DevFactory *dev = DevFactory::getInstance();
//dev.Register("CPU", creatCPU);
//dev.Register("GPU",creatGPU);
CPU * cpu = (CPU *)dev->GetClassInstanceByClassName("CPU"); //直接依据类名获取类的实例
cpu->print();
GPU *gpu = (GPU *)dev->GetClassInstanceByClassName("GPU");
gpu->print();
system("pause");
}
结果输出如下:
可以看出,利用全局变量的初始化,可以实现类在mian之前完成好注册。当然,也有其他的方式来实现这种机制,只是这种实现方法简单,优雅。