前不久写了个 C++ RTTI的简单实现(一) ,是在查了一些RTTI资料后自己倒腾出来的。近日重看(一两年前看的忘的东西挺多的)《深入浅出MFC》,看到候老师关于MFC六个仿真中的RTTI实现,对比了下自己的设计,下面总结一下。
相同点
整体的宏定义很类似,一个静态变量,一个虚函数返回真实类型。超级父类的特殊处理。
不同点
数据结构
MFC中用的是单链表,采用头插法建立链表。结构体内有三个指针:一个静态头指针,一个next指针,还有一个指向父类的指针。本人用的树形结构。一个父指针,一个兄弟指针,一个孩子指针。我的结构体设计的稍微啰嗦了一些。不过多出来的信息在某些情况下也是有用的,比如可以列出A类的所有派生类,并按照层次列出(觉得有用的可讨论)。
映射表
我的设计中有一张key为类名(字符串),value为类的runtimeclass地址的映射表,以此来定位某类在链表中的位置。MFC中用了头指针来访问链表。这一点不能说我的设计和MFC比没有一点优势,空间换时间嘛,在dynamic_cast的我这种实现会快一些,少一些搜索时间。
细节
在实现链接的时候,MFC用的是结构体的构造函数,我是用的模板函数,本质原因还是数据结构上的差异。另外MFC上的可以实现动态创建。我也进行一下修改,支持动态创建功能。
修改代码支持动态创建
改下结构体
class Shape;
////继承链结构体定义/////
typedef struct tagRTTI_Tree{
const char *pClassName;//类名
struct tagRTTI_Tree *pFather;//父亲
struct tagRTTI_Tree* pChild;//第一个派生类
struct tagRTTI_Tree* pBrothers;//兄弟类(同一个父亲)
Shape* (*createObj)();//+ 建构函数
}RTTI_Tree;
插入构造代码
///构造RTTI ID
#define MY_RTTI(CLASS_NAME) \
public: \
static RTTI_Tree s_RTTINode; \
static Shape* CreateObj(){return new CLASS_NAME;} \ //+
virtual const char * typeID(){return "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;
t.createObj=&MT::CreateObj;//+
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;
t.createObj=&MT::CreateObj;//+
//父亲信息更新
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;
}
测试
Shape* Load(const char *str){
RTTI_Tree *createObj=g_RTTI_Map[str];
if(createObj==NULL){
return NULL;
}else{
Shape *p1=createObj->createObj();
return p1;
}
}
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
//动态创建
Shape* c1=Load("DUCO|Circle");
Shape* c2=Load("DUCO|keke");
if(c1)
cout<<c1->typeID()<<endl;//DUCO|Circle
if(c2)//NULL
cout<<c2->typeID()<<endl;
getchar();
return 0;
}