Reflection in C++
前几天看一个java演示的设计模式讲解视频,里面提到了java中的反射机制,感觉反射这个东西很有意思,于是心血来潮想写一个C++中的反射。
反射机制可以简单地理解为:当需要一个类型的实例时,根据类型的名称就能得到一个实例。如下面的函数,
void* CreateClassInstance(const char *name);
这个函数可以根据传入的类型名称创建一个实例。
设计这样一个系统,我们需要对类型的名称和创建实例的方法(如构造函数)进行存储。当然,函数的返回值最好有实际意义,而不是一个无意义的void*。我们给可以被反射的类型取名叫ReflectableClass,ReflectableClass作为可被反射类型的基类。在这个class中需要对类型的名称和创建实例的方法进行存储,以便需要创建实例时可以进行查找。这里我们用map存储一个“键/值”对,“键”为类型的名称,“值”为创建实例的方法。
static std::map<std::string, FUNC_CREATE_INSTANCE> s_reflectors;
FUNC_CREATE_INSTANCE的定义如下,它是一个函数指针,所指向的函数不带参数。
typedef ReflectableClass* (*FUNC_CREATE_INSTANCE)();
这样便有了如下的类型声明:
class ReflectableClass { public: ReflectableClass() {} virtual ~ReflectableClass() {}
virtual const char* GetClassName() = 0;
static ReflectableClass* CreateClassInstance(const char* name); static bool AddInstanceCreator(const char*, FUNC_CREATE_INSTANCE);
private: static std::map<std::string, FUNC_CREATE_INSTANCE> s_reflectors; }; |
GetClassName用来返回每种可被反射的类型的名称,将其声明为纯虚函数,因为ReflectableClass被设计为一个抽象的类型。
CreateClassInstance用来根据传入的类型名称创建并返回一个实例。
AddInstanceCreator用来注册一个新类型。
当我们定义一个新的类型时,如定义一个Human类型,需要有种方式将类型的相关信息自动注册到ReflectableClass中。我们可以为新类型定义一个static的成员,在这个成员被初始化时将类型的信息注册制ReflectableClass中。定义一个新的类ClassInfo来完成这个工作。
class ClassInfo { public: ClassInfo(const char* name, FUNC_CREATE_INSTANCE creator); ~ClassInfo(); };
ClassInfo::ClassInfo(const char* name, FUNC_CREATE_INSTANCE creator) { ReflectableClass::AddInstanceCreator(name, creator); }
ClassInfo::~ClassInfo() {} |
Human的定义如下:
class Human: public ReflectableClass { public: Human(); virtual ~Human();
virtual const char* GetClassName(); static ReflectableClass* CreateInstance();
private: static ClassInfo s_classInfoHuman;
}; |
GetClassName是从ReflectableClass中继承并override的虚函数。CreateInstance用来创建Human的实例,即一个FUNC_CREATE_INSTANCE指向的函数。s_classInfoHuman用来注册Human的信息至ReflectableClass中。实现部分的代码如下:
ClassInfo Human::s_classInfoHuman(“Human”, Human::CreateInstance);
const char* Human::GetClassName() { return “Human”; }
ReflectableClass* Human::CreateInstance() { return new(std::nothrow) Human; } |
这样我们就完成了一个Human的定义和注册。当需要对Human进行反射时,只需调用“ReflectableClass::CreateClassInstance(“Human”)”即可。这里需要注意一个问题,需确保“ReflectableClass:: s_reflectors”的初始化工作在“Human::s_classInfoHuman”初始化前完成,否则会产生问题。我们可以将ReflectableClass和ClassInfo的定义和实现放在一个动态连接库中,当定义新类型时加载该库文件。
为方便在新类型中声明和实现static ClassInfo的对象及GetClassName、CreateInstance两个函数,可以定义一些自动化的宏。
完整的代码如下:
ReflectableClass.h
ReflectableClass.cpp
Human.h
Human.cpp