MFC的RTTI
来源:互联网 发布:奥尼尔06年总决赛数据 编辑:程序博客网 时间:2024/06/06 02:19
怎么设计RTTI呢?让我们想想,当你看到一种颜色,想知道的它的RGB成分比,不查色表行吗?当你持有一种产品,想知道它的型号,不查型录行吗?要到达RTTI的能力,我们(类库的设计者)一定要在类 构建 起来的时候,记录必要的信息,以建立型录。型录中的 类信息,最好以链表方式连接起来,将来方便一一比较。
我们这份“类别型录”的 链表元素 将以CRuntimeClass类来描述,CRuntimeClass类中至少需有类名称、链表的next指针、链表的first指针。由于first指针属于全局变量,所以它应该以static修饰之。除此之外,你所看到的其它CRuntimeClass成员都是为了其它目的而准备,陆陆续续我们会介绍出来。
- //in MFC.h
- struct CRuntimeClass
- {
- //Attributes
- LPCSTR m_lpszClassName;//类名称
- int m_nObjectSize;//对象大小
- UINT m_wSchema;
- CObject* (PASCAL* m_pfnCreateObject)();//函数指针
- CRuntimeClass* m_pBaseClass;//基类指针
- //CRuntimeClass对象以简单的链表形式链接在一起
- static CRuntimeClass* pFirstClass;//链表的first指针
- CRuntimeClass* m_pNextClass;//链表的next指针
- };
我希望,每一个类都能拥有这样一个CRuntimeClass成员变量,并且最好有一定的命名规则(在类名称之前冠以“class”作为它的名称),然后,经由 某种手段 将整个类库构建好之后,每个类中的CRuntimeClass成员变量能相互关联起来。
DECLARE_DYNAMIC / IMPLEMENT_DYNAMIC宏
为了神不知鬼不觉的把CRuntimeClass对象塞到类之中,并声明一个可以抓到该对象地址的函数,我们定义DECLARE_DYNAMIC宏如下:
- #define DECLARE_DYNAMIC(class_name)/
- public: /
- static CRuntimeClass class##classname;
- virtual CRuntimeClass* GetRuntimeClass() const;
- //出现在宏定义中的##,用来告诉编译器,把2个字符串系在一起,如果你这么使用此宏:
- DECLARE_DYNAMIC(CView),编译器为你做出的代码是:
- public: /
- static CRuntimeClass classCView;
- virtual CRuntimeClass* GetRuntimeClass() const;
这下子,只要在声明类时放入DECLARE_DYNAMIC宏即万事OK喽。不,还没有OK,类别型录的内容指定以及链接工作最好也能够神不知鬼不觉的,于是我们再定义IMPLEMENT_DYNAMIC宏:
- #define IMPLEMENT_DYNAMIC(class_name,base_class_name)
- _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NULL)
- //其中,_IMPLEMENT_RUNTIMECLASS又是一个宏。这样区分是因为这个宏在“动态创建”时还会用到。
- #define _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,wSchema,pfnNew)/
- static char _lpsz##class_name[]=#class_name;/
- CRuntimeClass class_name::class##class_name={/
- _lpsz##class_name,sizeof(class_name),wSchema,pfnNew,RUNTIME_CLASS(base_class_name),NULL};/
- static AFX_CLASSINIT _init_##class_name(&class_name::class##class_name);
- CRuntimeClass* class_name::GetRuntimeClass() const;/
- {return &class_name::class##class_name;}
- //其中:RUNTIME_CLASS宏定义如下:
- #define RUNTIMEC_CLASS(class_name)/
- (&class_name::class##class_name)
- //看起来整个IMPLEMENT_DYNAMIC内容好像只是指定初值,其实不然,其美妙处在于它所使用的一个struct AFX_CLASSINIT,定义如下:
- struct AFX_CLASSINIT
- {AFX_CLASSINIT(CRuntimeClass* pNewClass);}//这表示它有一个构造函数(不必惊讶,C++的struct和class都有构造函数),定义如下:
- AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass* pNewClass)
- {
- pNewClass->m_pNextClass=CRuntimeClass::pFirstClass;
- CRuntimeClass::pFirstClass=pNewClass;
- }
- //很明显,此构造函数负责linked list的链接工作。整组宏看起来有点吓人,文字代换而已,没什么可怕的。
于是乎,程序中只需要简简单单的2个宏,DECLARE_DYNAMIC(Cxxx)和IMPLEMENT_DYNAMIC(Cxxx,Cxxxbase)就完成了构建数据并加入链表的工作。
链表的头总是需要特别费心处理,不能够套用一般的链表行为方式。我们的类根源CObject,不能套用现成的宏ECLARE_DYNAMIC和IMPLEMENT_DYNAMIC必须特别设计如下:
- //in header file
- class CObject
- {
- public:
- virtual CRuntimeClass* GetRuntimeClass() const;
- ...
- public:
- static CRuntimeClass classCObject;
- };
- //in implement file
- static char szCObject[]="CObject";
- struct CRuntimeClass CObject::classCObject=
- {szCObject,sizeof(CObject),0xFFFF,NULL,NULL,NULL};
- static AFX_CLASSINIT _init_CObject(&CObject::classCObject);
- CRuntimeClass* CObject::GetRuntimeClass const
- {
- return &CObject::classCObject;
- }
- //并且CRuntimeClass中的静态成员需要初始化
- CRuntimeClass* CRuntimeClass::pFirstClass=NULL;
- //这样,“类别型录”链表的头部就形成了。
终于,整个“类别型录”链表的头部就这样形成了。
IsKindOf(类型识别)
有了“类别型录”网,要实现IsKindOf功能,再轻松不过了。
1、为CObject加上一个IsKindOf函数,于是此函数将被所有类继承。该函数将把参数指定的某个CRuntimeClass对象拿来与“类别型录”中的元素一一比较。比较成功(在型录中发现),就传回true,否则传回FALSE:
- //in header file
- class CObject
- {
- public:
- BOOL IsKindOf(const CRuntimeClass* pClass) const;
- };
- //in implementation file
- BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
- {
- CRuntimeClass* pClassThis=GetRuntimeClass();
- while(pClassThis!=NULL)
- {
- if(pClassThis==pClass)
- return true;
- pClassThis=pClassThis->m_pBaseClass;
- }
- return false;//walked to the top,no match
- }
注意:while循环中所追踪的是“同宗”路线,也就是凭着m_pBaseClass而非m_pNextClass,假设我们的调用是:CView* pView=new CView; pView->IsKindOf( RUNTIME_CLASS(CWinApp) );,其中RUNTIME_CLASS是一个宏,替换后为&CWinApp::classCWinApp。函数内部利用GetRuntimeClass先取得&CView::classCView,然后巡线而上(所谓巡线分别是指CView、CWnd、CCmdTarget、CObject),没获得一个CRuntimeClass对象指针,就拿来和CView::classCView的指针比较,靠这个土方法,完成了IsKindOf的能力。
2、IsKindOf的使用方法如下:
- CMyDoc* pMyDoc=new CMyDoc;
- CMyView* pMyView=new CMyView;
- cout<<pMyDoc->IsKindof(RUNTIME_CLASS(CMyDoc));//true
- cout<<pMyDoc->IsKindof(RUNTIME_CLASS(CDocument));//true
- cout<<pMyDoc->IsKindof(RUNTIME_CLASS(CCmdTarget));//true
- cout<<pMyDoc->IsKindof(RUNTIME_CLASS(CObject));//true
- cout<<pMyDoc->IsKindof(RUNTIME_CLASS(CWinApp));//false
- cout<<pMyDoc->IsKindof(RUNTIME_CLASS(CView));//false
- cout<<pMyView->IsKindof(RUNTIME_CLASS(CView));//true
- cout<<pMyView->IsKindof(RUNTIME_CLASS(CObject));//true
- cout<<pMyView->IsKindof(RUNTIME_CLASS(CWnd));//true
- cout<<pMyView->IsKindof(RUNTIME_CLASS(CFrameWnd));//false
- MFC的RTTI
- MFC的RTTI实现
- MFC的RTTI
- MFC的RTTI实现
- MFC的RTTI实现
- MFC的RTTI实现机制!
- MFC的RTTI实现机制!
- 深入浅出MFC:MFC中的的RTTI实现
- 关于MFC中RTTI的理解
- 091014(星期三)MFC的RTTI
- 支持类模板的 MFC RTTI 宏
- MFC中的的RTTI和动态创建
- MFC rtti 学习笔记
- 关于MFC中的RTTI
- MFC深入浅出之RTTI
- MFC-RTTI
- MFC RTTI 实现
- MFC RTTI 宏
- Paxos算法与Zookeeper分析
- POJ 题目3370 Halloween treats(鸽巢原理)
- Static用法说明
- Android ActionBar详解
- Fragment生命周期
- MFC的RTTI
- PL/SQL Developer使用技巧、快捷键
- 【bzoj 2179】FFT
- 依赖注入及AOP简述系列文章
- UVa 193 图着色
- 设计模式 策略模式 以角色游戏为背景
- 浅谈JBPM-Java Business Process Management
- Java异常分析
- Sping简述