用过java的开发者都知道,java有一种叫做反射的功能,可以根据类名来生成类的实例,这种机制的好处就是可以在不修改代码的情况下,可以通过配制文件来决定生成什么类的对像。那么对于使用C++开的人来说,有没有一种方式实现类似的功能呢?
虽然C++没有从语言层面提供反射的机制,但是还是可以简单的模拟出类似的功能的。在查找了很多资料,也看过很多人写的不同实现后,将其中一种我认为模拟的比较好的方案做个总结。
首先定义一个ClassInfo类:
typedef Resource* (*ResourceConstructorFn)(void); class ClassInfo { public: ClassInfo(int type, ResourceConstructorFn creator):m_creator(creator) { Resource::regist(this); } Resource* create_resource() { return m_creator ? (*m_creator)() : 0; } ResourceConstructorFn m_creator; };
Resource类便是我们需要反射创建的类的基类了。定义如下:
class Resource { public: Resource(); virtual ~Resource() = 0; static Resource* get_resource(string name)
{
if(m_map_resource.find(name) != m_map_resource.end())
{
Resource* res = m_map_resource[name]->create_resource();
return res;
}
else
{
return NULL;
}
}
static void regist(ClassInfo* ci) { if(ci) { if(m_map_resource.find(ci->m_type) == m_map_resource.end()) { m_map_resource[ci->m_type] = ci; } } } protected: static std::map<string, ClassInfo*> m_map_resource; //资源类型与其类信息map,用于创建资源子类 };
ClassInfo类的构造函数里会将自身注册到Resource基类当中,然后Resource类的get_resource(string name)函数就可以根据注册的信息创建对应的Resource子类了。因此,我们只需让所有Resource子类都有一个ClassInfo对像就行了。于是添加以下宏来实现:
//用于创建资源,所有继承Resource类的子类,其定义结尾应当加此宏。 #define DECLARE_RESOURCE(class_name) \ private:\ static ClassInfo ci; \ public:\ ClassInfo* get_class_info(){return &ci;}\ static Resource* create_resource(){return new class_name();} //绑定资源及其类型,用于创建资源,所有继承Resource类的子类,其实现中应当加此宏。 #define BIND_RESOURCE_TYPE(class_name, name) \ ClassInfo name::ci(name, (ResourceConstructorFn)&class_name::create_resource);
class A:Resouce
{
DECLARE_RESOURCE(A)
};
BIND_RESOURCE_TYPE(A, "A")
只要在扩展每个Resource的子类的时候,都加入DECLARE_RESOURCE和BIND_RESOURCE_TYPE这两个宏,由于静态变量会在程序执行最开始就初始化,也就是A类的ci成员会在一开始就将create_resource()函数注册到Resource基类的m_map_resource中,
所以,要得到A类的实例,变只需要根据类名调用Resource::get_resource("A")即可。
虽然实现逻辑有点复杂,还需要在定义子类时加入两个宏,但是还是可以模拟一下反射的功能的。