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

动机

为了加深对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)

//Circle
class Circle:public Shape {
    MY_RTTI(Circle);
private:
    void priFun2(){};
};
END_DECLARE_CLASS(Circle,Shape)

//Rect
class Rect:public Shape {
    MY_RTTI(Rect);
private:
    void priFun2(){};
};
END_DECLARE_CLASS(Rect,Shape)

//Red-Rect
class 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);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值