C++ RTTI的简单实现(一)

来源:互联网 发布:js同源策略和跨越请求 编辑:程序博客网 时间:2024/05/20 02:56

动机

为了加深对RTTI的理解,尝试实现了一个RTTI系统。不过做的比较简陋,功能如下

  • 1.只支持单继承体系
  • 2.系统必须有个超级类,作为一切类的最上层父类
  • 3.手动添加MY_RTTI和END_SUPER_DECLARE_CLASS宏
  • 4.实现了动态造型(dynamic_cast)

介绍

typeID的识别利用虚函数实现,利用虚函数的性质可以让对象输出真正的类型标志,而不会被其声明的类型所改变。为了安全的造型,实现了一个继承链。在系统内,每个类的声明里会加上一个s_RTTINode,用于存储继承信息,包括本类名,父亲的继承信息和派生类等继承信息。这样继承的关系就被串联起来了。定义如下:

////继承链结构体定义/////typedef struct tagRTTI_Tree{    const char *pClassName;//类名    struct tagRTTI_Tree *pFather;//父亲    struct tagRTTI_Tree* pChild;//第一个派生类    struct tagRTTI_Tree* pBrothers;//兄弟类(同一个父亲)}RTTI_Tree; // 单继承结构如下: //        A //    /       \ //  B            C //  |         /    \ //  D       E       F    //

另外为了快速向上造型,对整个树进行了索引。如E可以向上为A和C,但是不允许为B。

源码

#include<iostream>#include<vector>#include<string>#include<hash_map>using namespace std;////继承链结构体定义/////typedef struct tagRTTI_Tree{    const char *pClassName;//类名    struct tagRTTI_Tree *pFather;//父亲    struct tagRTTI_Tree* pChild;//第一个派生类    struct tagRTTI_Tree* pBrothers;//兄弟类(同一个父亲)}RTTI_Tree;///////////////////////////////////////////////////////////////////RTTI实现////////////////////////////////////////////////////////继承链节点索引hash_map<string,RTTI_Tree*> g_RTTI_Map;///构造RTTI ID#define MY_RTTI(CLASS_NAME) \public: \    static RTTI_Tree s_RTTINode; \    virtual const char * typeID(){return "DUCO|"#CLASS_NAME;} //构造RTTI继承结构#define END_DECLARE_CLASS(CLASS_NAME,F_CLASS_NAME) \    RTTI_Tree CLASS_NAME::s_RTTINode=RTTI_Create_Link<CLASS_NAME,F_CLASS_NAME>("DUCO|"#CLASS_NAME);//构造RTTI继承结构#define END_SUPER_DECLARE_CLASS(CLASS_NAME) \    RTTI_Tree CLASS_NAME::s_RTTINode=RTTI_Create_Link<CLASS_NAME>("DUCO|"#CLASS_NAME);//构造继承链 超级父亲template<class MT>RTTI_Tree RTTI_Create_Link(const char *pName){    RTTI_Tree t;    t.pClassName=pName;    string str(pName);    g_RTTI_Map[str]=&(MT::s_RTTINode);    t.pFather=NULL;    t.pBrothers=NULL;    t.pChild=NULL;    return t;}//构造继承链 普通类template<class MT,class FT>RTTI_Tree RTTI_Create_Link(const char *pName){    RTTI_Tree t;    RTTI_Tree *pCur;    t.pClassName=pName;//类名    t.pFather=&(FT::s_RTTINode);//父亲类    t.pChild=NULL;    t.pBrothers=NULL;    //父亲信息更新    if(FT::s_RTTINode.pChild==NULL)//第一个孩子        FT::s_RTTINode.pChild=&(MT::s_RTTINode);    else{        pCur=FT::s_RTTINode.pChild;        while (pCur->pBrothers)//找到最后一个孩子            pCur=pCur->pBrothers;        pCur->pBrothers=&(MT::s_RTTINode);    }    //映射表,索引整棵树    string str(pName);    g_RTTI_Map[str]=&(MT::s_RTTINode);    return t;}///////////////////////////////////////////////////////////////////dynamic_cast 实现//////////////////////////////////////////////////////template<class Type,class S>//待转化类和super类Type *my_dynamic_cast(S *s){    const char *pMyID=s->typeID();//获取本类ID    string str(pMyID);    RTTI_Tree *pCurTree=g_RTTI_Map [str];    //可转化类型为自己真实类和其父辈类型    while(pCurTree){        if(strcmp(pCurTree->pClassName,Type::s_RTTINode.pClassName)==0)            return (Type*)(s);        pCurTree=pCurTree->pFather;    }    return NULL;}///////////////////////////////////////////////////////////////////demo///////////////////////////////////////////////////////// 说明 1.只支持单继承体系///      2.系统必须有个超级类,作为一切类的最上层父类///      3.手动添加MY_RTTI和END_SUPER_DECLARE_CLASS宏///      4.实现了动态造型//Base 类class Shape {    MY_RTTI(Shape);private:    void priFun1(){};};END_SUPER_DECLARE_CLASS(Shape)//Circleclass Circle:public Shape {    MY_RTTI(Circle);private:    void priFun2(){};};END_DECLARE_CLASS(Circle,Shape)//Rectclass Rect:public Shape {    MY_RTTI(Rect);private:    void priFun2(){};};END_DECLARE_CLASS(Rect,Shape)//Red-Rectclass RedRect:public Rect {    MY_RTTI(RedRect);private:    void priFun2(){};};END_DECLARE_CLASS(RedRect,Rect) // //       Shape //    /        \ //  Rect       Circle //   |          //  RedRect    //int main(){    //获取真实类型    Shape *s1,*s2,*s3;    s1=new Shape();    s2=new Circle();    s3=new RedRect();    cout<<s1->typeID()<<endl;// DUCO|Shape    cout<<s2->typeID()<<endl;// DUCO|Circle    ///动态造型    auto *t1=my_dynamic_cast<Circle,Shape>(s1);//实际内容为Shape想转为CirCle     cout<<(int*)t1<<endl;//NULL    auto *t2=my_dynamic_cast<Circle,Shape>(s2);//实际内容为CirCle想转为CirCle     cout<<(int*)t2<<endl;//SUCCESS    auto *t3=my_dynamic_cast<Rect,Shape>(s2);//实际内容为CirCle想转为Rect(兄弟)     cout<<(int*)t3<<endl;//NULL    auto *t4=my_dynamic_cast<Rect,Shape>(s3);//实际内容为RedRect想转为Rect(直系)     cout<<(int*)t4<<endl;//SUCCESS    auto *t5=my_dynamic_cast<Circle,Shape>(s3);//实际内容为RedRect想转为Circle(非直系)     cout<<(int*)t5<<endl;//NULL    getchar();    return 0;}

后记

昨天晚上查了一些RTTI的资料,其实自己理解的还不够深刻。据说c++对象模型那本书有详细,可能会过短时间再看一下,把自己的实现改进一些,比如支持多继承等。

另外记录下在实现时遇到的困难。刚开始没有理清思路,若想获取一个类的真实信息,需要使用虚函数来实现。如果使用类的静态变量或者函数是没办法实现的,因为使用静态变量前提是我要知道类信息,而我本来的需求就是动态去获取类信息。所以c++的dynamic_cast依赖于虚表。我的实现虽然没有直接利用虚表,但是建立的继承链本质上是利用了虚表(用其内容构建索引)。

而继承链又是另一回事了,继承链可以认为是静态的。它存储的是类之间的关系,跟具体对象无关。所以最后实现是在类声明中嵌入一个静态变量。最后因为要初始化静态变量,我需要实现一个初始化函数,而这个函数的变量是类名,所以可以看到我这部分实现不得不使用模板函数:template<class MT>RTTI_Tree RTTI_Create_Link(const char *pName);

0 0
原创粉丝点击