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
- C++ RTTI的简单实现(一)
- 一个简单的RTTI实现
- 一个简单的RTTI实现
- 一个简单的C++的RTTI实现
- C++ RTTI的简单实现(二)
- MFC的RTTI实现
- 一种 RTTI 的实现
- MFC的RTTI实现
- MFC的RTTI实现
- D2010 RTTI + Attribute 简单实现ORM
- D2010 RTTI + Attribute 简单实现ORM
- D2010 RTTI + Attribute 简单实现ORM
- Delphi2010 RTTI + Attribute 简单实现ORM实例
- MFC的RTTI实现机制!
- MFC的RTTI实现机制!
- 用DELPHI的RTTI实现数据集的简单对象化
- 用DELPHI的RTTI实现数据集的简单对象化
- (转贴)用DELPHI的RTTI实现数据集的简单对象化
- 剑指offer-面试题55-字符流中第一个不重复的字符
- 错误代码为 0x80072EFD,可在需要时使用 win10应用商店问题
- 5.剑指offer-链表复制
- PHP设计模式系列(二):装饰模式
- ubuntu配置环境
- C++ RTTI的简单实现(一)
- Maven项目不能部署到Tomcat
- OKHttp使用详解
- 关于棋牌游戏遇到的问题解决日志1
- 在salesforce中更换自定义app的logo
- 消息队列
- Dynamics CRM2016 通过web api来调用自定义action之global action
- hebernate提示主键ID这一列不能为null
- HDFS --操作命令详解