支持多基类的C++类反射实现

本文中的类反射指的是实例的类型识别(RTTI)、动态创建,继承链遍历能力,不讨论成员函数、成员变量等的反射。即实现以下类似接口:

class Foo : public Object { }; Object *obj1 = new Foo(); IsKindOf(obj1, "Foo"); // 类型识别 Object *obj2 = CreateObject("Foo"); // 动态创建 GetBaseClass(obj1) == "Object"

C++没有提供反射特性,但是依靠C++强大的语言特性,我们可以自己实现,本文包括以下内容:

  • 一种类反射实现方式 (MFC方式)
  • 使用模板实现多基类反射

一种类反射实现方式

本小节实现类反射的三大能力:实例类型识别动态创建继承链遍历。为了类继承结构的组织方便,实现了类反射的类通常会有一个公共基类,例如在MFC中就是CObject。我们定义一个公共基类:

class Object { public: virtual ~Object() { } };

首先实现实例类型识别实例类型识别可以考虑使用typeid(instance).name()来实现,但是需要该类具有虚函数表,并且返回值也是编译器相关的,而不是真正的类名。我们在每个类中添加一个静态成员变量来存储类信息,并定义一个虚函数时每个实例可以正确获取到类信息。为了实现方便,这里定义一个ClassInfo类来表示类信息:

class ClassInfo { public: explicit ClassInfo(const std::string& className) : m_className(className) { } const std::string& GetClassName() const { return m_className; } bool IsKindOf(const std::string& className) const { return m_className == className; } private: std::string m_className; };

在每个类中添加一个静态成员变量和虚函数:

// .h class Foo : public Object { public: virtual ClassInfo* GetClassInfo() const { return &ms_classInfo; } static ClassInfo ms_classInfo; }; // .cpp ClassInfo Foo::ms_classInfo("Foo");

这样我们就简单地实现了实例类型识别,可以做如下测试:

Object *obj = new Foo(); assert(obj->GetClasInfo()->IsKindOf("Foo"));

然后实现动态创建能力,先定义接口,添加了成员函数FindClass(静态)和CreateObject:

ClassInfo* fooInfo = ClassInfo::FindClass("Foo"); assert(fooInfo); Object* obj = fooInfo->CreateObject();

定义一个hash单例,存储类名到ClassInfo的映射,FindClass使用该hash表查找。ClassInfo并不知道如何创建实例,需要我们在每个类中添加CreateObject,然后传递给ClassInfo。

+typedef Object* (*ObjectConstructor)(void); class ClassInfo { public: + typedef boost::unordered_map<std::string, ClassInfo*> ClassInfoHashTable; explicit ClassInfo(const std::string& className, + ObjectConstructor ctor) : m_className(className), + m_objectCtor(ctor) { + Register(); } const std::string& GetClassName() const { return m_className; } bool IsKindOf(const std::string& className) const { return m_className == className; } + Object* CreateObject() const + { + return m_objectCtor ? (*m_objectCtor)() : NULL; + } + static ClassInfo* FindClass(const std::string& className) + { + ClassInfoHashTable& table = Singleton<ClassInfoHashTable>::instance(); + if (iter == table.end()) return NULL; + return iter->second; + } private: + void Register() + { + ClassHashTable& table = Singleton<ClassInfoHashTable>::instance(); + table.insert(makepair(m_classname, this)); + } std::string m_className; + ObjectConstructor m_objectCtor; }; // .h class Foo : public Object { public: virtual ClassInfo* GetClassInfo() const { return &ms_classInfo; } + static Object* CreateObject() + { + return new Foo(); // 需要有默认构造函数 + } static ClassInfo ms_classInfo; }; // .cpp ClassInfo Foo::ms_classInfo("Foo", (ObjectConstructor)(Foo::CreateObject));

最后,在ClassInfo中加入继承链遍历(为了简化问题,只考虑单继承):

class ClassInfo { public: explicit ClassInfo(const std::string& className, ObjectConstructor ctor, + const ClassInfo *baseInfo) : m_className(className), m_objectCtor(ctor), + m_baseInfo(baseInfo) { Register(); } + const ClassInfo* GetBaseClass() const + { + return m_baseInfo; + } private: + const ClassInfo *m_baseInfo; ... }; // .cpp ClassInfo Foo::ms_classInfo("Foo", (ObjectConstructor)(Foo::CreateObject), + &Object::ms_classInfo);

现在我们已经实现了所有的功能,也可以继续给ClassInfo添加一些有用的接口,例如IsKindOf等。但是,实际使用时每个类都要手动写这么多代码是很麻烦的,使用宏可以帮我们简化:

typedef Object* (*ObjectConstructor)(void); #define DECLARE_CLASS(name) \ public: \ static ClassInfo ms_classInfo; \ virtual ClassInfo* GetClassInfo() const; \ static Object* CreateObject() #define IMPLEMENT_CLASS(name, basename) \ ClassInfo name::ms_classInfo(#name, \ (ObjectConstructor)(name::CreateObject), \ &basename::ms_classInfo) \ ClassInfo* name::GetClassInfo() const \ { \ return &name::ms_classInfo; \ } \ Object* name::CreateObject() \ { \ return new name(); \ } // .h class Foo : public Object { public: DECLARE_CLASS(Foo) }; // .cpp IMPLEMENT_CLASS(Foo, Object)

本文只是为了阐述思路,实际使用时还需要根据类的特征来定制不同的宏(是否支持动态创建,多基类支持等)。

使用模板实现多基类反射

上文中实现的类反射需要所有的类拥有一个共同基类,但是有时候一个工程中可能需要使用多套类继承体系,这时又需要重写一套反射类和宏。我们可以使用模板定制一个更灵活的类反射系统。类信息ClassInfo需要加一个模板参数作为该组的共同基类:

template <class _GroupBase> class ClassInfo { public: _GroupBase* CreateObject() const; ... };

具体实现不再赘述,附上代码:link

posted @ 2014-02-18 10:16  Echo.Zhao  阅读(1199)  评论(0编辑  收藏  举报