RTTI运行时类型识别
概述
RTTI(Run-Time Type Identification),通过运行时类型信息程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型。。面向对象的编程语言,像C++,Java,delphi都提供了对RTTI的支持。
本文主要介绍C++的RTTI以及MFC相关的RTTI。
1、C++
1)typeid操作符,返回指针和引用所指的实际类型。
2)dynamic_cast操作符,将基类类型的指针或引用安全地转换为派生类型的指针或引用。
1 #include <iostream> 2 using namespace std; 3 class Base {}; 4 class Derived: public Base {}; 5 int main() 6 { 7 Base b, *pb; 8 pb = NULL; 9 Derived d; 10 cout << typeid(int).name() << endl << typeid(unsigned).name() << endl 11 << typeid(long).name() << endl << typeid(unsigned long).name() << endl 12 << typeid(char).name() << endl << typeid(unsigned char).name() << endl 13 << typeid(float).name() << endl << typeid(double).name() << endl 14 << typeid(string).name() << endl << typeid(Base).name() << endl 15 << typeid(b).name()<<endl << typeid(pb).name()<<endl 16 << typeid(Derived).name() << endl << typeid(d).name()<<endl 17 << typeid(type_info).name() << endl; 18 19 return 0; 20 }
2、模拟MFC
有些人会有疑问,C++已经有RTTI了,为什么MFC还要实现一套自己的RTTI,原因时MFC开发的时候,C++标准还比较老,还没有这方面的内容,所以MFC自己实现了一套。以下模拟MFC的方式实现一套RTTI。
----------------------------runtimeclass.h------------------------------
1 #ifndef _RTTIAPP_RUNTIMECLASS_H 2 #define _RTTIAPP_RUNTIMECLASS_H 3 4 #include "datatype.h" 5 6 class CObject; 7 8 struct CRuntimeClass 9 { 10 // Attributes 11 LPCSTR m_lpszClassName; 12 int m_nObjectSize; 13 UINT m_wSchema; // schema number of the loaded class 14 CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class 15 CRuntimeClass* m_pBaseClass; 16 17 // CRuntimeClass objects linked together in simple list 18 static CRuntimeClass* pFirstClass; // start of class list 19 CRuntimeClass* m_pNextClass; // linked list of registered classes 20 }; 21 22 struct AFX_CLASSINIT 23 { AFX_CLASSINIT(CRuntimeClass* pNewClass); }; 24 25 #define RUNTIME_CLASS(class_name) \ 26 (&class_name::class##class_name) 27 28 #define DECLARE_DYNAMIC(class_name) \ 29 public: \ 30 static CRuntimeClass class##class_name; \ 31 virtual CRuntimeClass* GetRuntimeClass() const; 32 33 #define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew) \ 34 static char _lpsz##class_name[] = #class_name; \ 35 CRuntimeClass class_name::class##class_name = { \ 36 _lpsz##class_name, sizeof(class_name), wSchema, pfnNew, \ 37 RUNTIME_CLASS(base_class_name), NULL }; \ 38 static AFX_CLASSINIT _init_##class_name(&class_name::class##class_name); \ 39 CRuntimeClass* class_name::GetRuntimeClass() const \ 40 { return &class_name::class##class_name; } \ 41 42 #define IMPLEMENT_DYNAMIC(class_name, base_class_name) \ 43 _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL) 44 45 #endif
-------------------------------runtimeclass.cpp---------------------------------------------
1 #include "runtimeclass.h" 2 3 CRuntimeClass* CRuntimeClass::pFirstClass = NULL; 4 5 AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass* pNewClass) 6 { 7 pNewClass->m_pNextClass = CRuntimeClass::pFirstClass; 8 CRuntimeClass::pFirstClass = pNewClass; 9 }
------------------------------object.h----------------------------------------------------------
1 #ifndef _RTTIAPP_OBJECT_H_ 2 #define _RTTIAPP_OBJECT_H_ 3 4 #include "runtimeclass.h" 5 6 class CObject 7 { 8 public: 9 CObject::CObject() { 10 } 11 CObject::~CObject() { 12 } 13 14 virtual CRuntimeClass* GetRuntimeClass() const; 15 BOOL IsKindOf(const CRuntimeClass* pClass) const; 16 17 public: 18 static CRuntimeClass classCObject; 19 }; 20 21 #endif
-------------------------------------------object.cpp----------------------------
1 #include "object.h" 2 #include "runtimeclass.h" 3 4 static char szCObject[] = "CObject"; 5 struct CRuntimeClass CObject::classCObject = 6 { szCObject, sizeof(CObject), 0xffff, NULL, NULL }; 7 8 static AFX_CLASSINIT _init_CObject(&CObject::classCObject); 9 10 CRuntimeClass* CObject::GetRuntimeClass() const 11 { 12 return &CObject::classCObject; 13 } 14 15 BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const 16 { 17 CRuntimeClass* pClassThis = GetRuntimeClass(); 18 while (pClassThis != NULL) 19 { 20 if (pClassThis == pClass) 21 return TRUE; 22 pClassThis = pClassThis->m_pBaseClass; 23 } 24 return FALSE; // walked to the top, no match 25 }
---------------------------------main.cpp-------------------------------------
1 #include <iostream> 2 #include "object.h" 3 #include "runtimeclass.h" 4 5 using namespace std; 6 7 class CGraphics : public CObject 8 { 9 DECLARE_DYNAMIC(CGraphics) 10 }; 11 12 class CLine : public CGraphics 13 { 14 DECLARE_DYNAMIC(CLine) 15 }; 16 17 class CRectangle : public CGraphics 18 { 19 DECLARE_DYNAMIC(CRectangle) 20 }; 21 22 IMPLEMENT_DYNAMIC(CRectangle, CGraphics) 23 IMPLEMENT_DYNAMIC(CLine, CGraphics) 24 IMPLEMENT_DYNAMIC(CGraphics, CObject) 25 26 int main() 27 { 28 CRectangle *pRect = new CRectangle(); 29 CLine *pLine = new CLine(); 30 31 cout << "pRect->IsKindOf(RUNTIME_CLASS(CGraphics)): " << pRect->IsKindOf(RUNTIME_CLASS(CGraphics)) <<endl; 32 33 cout << "pLine->IsKindOf(RUNTIME_CLASS(CGraphics)): " << pLine->IsKindOf(RUNTIME_CLASS(CGraphics)) <<endl; 34 35 cout << "pLine->IsKindOf(RUNTIME_CLASS(CRectangle)): " << pLine->IsKindOf(RUNTIME_CLASS(CRectangle)) <<endl; 36 }
运行结果
完整源码
http://git.oschina.net/zhujf21st/RTTIApp
3、直接使用MFC的情况
1 #include <iostream> 2 #include <afx.h> 3 4 using namespace std; 5 6 class CGraphics : public CObject 7 { 8 DECLARE_DYNAMIC(CGraphics) 9 }; 10 11 class CLine : public CGraphics 12 { 13 DECLARE_DYNAMIC(CLine) 14 }; 15 16 class CRectangle : public CGraphics 17 { 18 DECLARE_DYNAMIC(CRectangle) 19 }; 20 21 IMPLEMENT_DYNAMIC(CRectangle, CGraphics) 22 IMPLEMENT_DYNAMIC(CLine, CGraphics) 23 IMPLEMENT_DYNAMIC(CGraphics, CObject) 24 25 int main() 26 { 27 CRectangle *pRect = new CRectangle(); 28 CLine *pLine = new CLine(); 29 30 cout << "pRect->IsKindOf(RUNTIME_CLASS(CGraphics)): " << pRect->IsKindOf(RUNTIME_CLASS(CGraphics)) <<endl; 31 32 cout << "pLine->IsKindOf(RUNTIME_CLASS(CGraphics)): " << pLine->IsKindOf(RUNTIME_CLASS(CGraphics)) <<endl; 33 34 cout << "pLine->IsKindOf(RUNTIME_CLASS(CRectangle)): " << pLine->IsKindOf(RUNTIME_CLASS(CRectangle)) <<endl; 35 }
完整源码
https://git.oschina.net/zhujf21st/RTTIAppUsingMFC.git