首页 > 代码库 > MFC中的运行时类型识别(RTTI)
MFC中的运行时类型识别(RTTI)
RTTI是Runtime Type Identification的缩写,中文名为“运行时类型识别”。
MFC早在编译器支持RTTI之前,就有了这种能力。我们现在要以相同的手法,在Console程序中仿真出来。我希望我的类库具备IsKindOf 的能力,能在执行期侦测到某个对象是否属于某个类,并传回TRUE 或 FALSE。以形状 Shape为例 ,我希望:
即 长方形属于“长方形类”,正方形属于“长方形类”,圆不属于“长方形类”,原因是长方形派生 正方形类。
CMyDoc 属于“CMyDoc类”,CMyDoc也属于“CDocument类”,CMyDoc也属于“CCmdTarget类” ,CMyDoc不属于“CWnd类” 。原因是CCmdTarget派生CDocument类,CDocument派生 CMyDoc类。
同时,我希望,每一个类都能拥有这样一个CRuntimeClass 成员变量,并且最后有一定的命名规则(例如,在类名称之前冠以“class”作为它的名称),然后,经由某种手段将整个类库构建好之后,“类别型录”就能呈现如下图(2)所示的面貌:
图(2)“类别型录”的链表形式
下面,以控制台应用程序Frame3为例,模拟mfc的RTTI功能。
在案例Frame3 的cpp 文件中,有这样的操作:
IMPLEMENT_DYNAMIC(CCmdTarget,CObject) IMPLEMENT_DYNAMIC(CWinThread,CCmdTarget) IMPLEMENT_DYNAMIC(CWinApp,CWinThread) IMPLEMENT_DYNAMIC(CWnd,CCmdTarget) //其实在MFC中此句是,IMPLEMENT_DYNCREATE() IMPLEMENT_DYNAMIC(CFrameWnd,CWnd) //其实在MFC中此句是,IMPLEMENT_DYNCREATE() IMPLEMENT_DYNAMIC(CDocument,CCmdTarget) IMPLEMENT_DYNAMIC(CView,CWnd)
为了证明,程序中存在整个“类别型录网”。我在main函数中调用 PrintAllClasses ,把链表中的每一个元素的类名称、对象大小,以及scheme.no,打印出来。
void PrintAllClasses() //输出“类别型录网“ { CRuntimeClass* pClass; //just walk through the simple list of registered classes for(pClass = CRuntimeClass::pFirstClass; pClass!=NULL; pClass = pClass->m_pNextClass) { cout<<pClass->m_lpszClassName<<"\n"; cout<<pClass->m_nObjectSize<<"\n"; cout<<pClass->m_wSchema<<"\n"; } }
效果如下:
图(4)链表中的每一个元素的类名称、对象大小,以及scheme.no,说明存在该“类别型录网”
详细代码如下:
//mfc.h
#define BOOL int #define TRUE 1 #define FALSE 0 #define LPCSTR LPSTR typedef char* LPSTR; #define UINT int #define PASCAL _stdcall #include <iostream.h> class CObject; struct CRuntimeClass { // Attributes LPCSTR m_lpszClassName; int m_nObjectSize; UINT m_wSchema; // schema number of the loaded class CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class CRuntimeClass* m_pBaseClass; // CRuntimeClass objects linked together in simple list static CRuntimeClass* pFirstClass; // start of class list CRuntimeClass* m_pNextClass; // linked list of registered classes }; struct AFX_CLASSINIT { AFX_CLASSINIT(CRuntimeClass* pNewClass); }; #define RUNTIME_CLASS(class_name) (&class_name::class##class_name) #define DECLARE_DYNAMIC(class_name) public: static CRuntimeClass class##class_name; virtual CRuntimeClass* GetRuntimeClass() const; #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; } #define IMPLEMENT_DYNAMIC(class_name, base_class_name) _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL) class CObject { public: CObject::CObject() { } CObject::~CObject() { } virtual CRuntimeClass* GetRuntimeClass() const; public: static CRuntimeClass classCObject; }; class CCmdTarget : public CObject { DECLARE_DYNAMIC(CCmdTarget) public: CCmdTarget::CCmdTarget() { } CCmdTarget::~CCmdTarget() { } }; class CWinThread : public CCmdTarget { DECLARE_DYNAMIC(CWinThread) public: CWinThread::CWinThread() { } CWinThread::~CWinThread() { } virtual BOOL InitInstance() { return TRUE; } virtual int Run() { return 1; } }; class CWnd; class CWinApp : public CWinThread { DECLARE_DYNAMIC(CWinApp) public: CWinApp* m_pCurrentWinApp; CWnd* m_pMainWnd; public: CWinApp::CWinApp() { m_pCurrentWinApp = this; } CWinApp::~CWinApp() { } virtual BOOL InitApplication() { return TRUE; } virtual BOOL InitInstance() { return TRUE; } virtual int Run() { return CWinThread::Run(); } }; class CDocument : public CCmdTarget { DECLARE_DYNAMIC(CDocument) public: CDocument::CDocument() { } CDocument::~CDocument() { } }; class CWnd : public CCmdTarget { DECLARE_DYNAMIC(CWnd) public: CWnd::CWnd() { } CWnd::~CWnd() { } virtual BOOL Create(); BOOL CreateEx(); virtual BOOL PreCreateWindow(); }; class CFrameWnd : public CWnd { DECLARE_DYNAMIC(CFrameWnd) public: CFrameWnd::CFrameWnd() { } CFrameWnd::~CFrameWnd() { } BOOL Create(); virtual BOOL PreCreateWindow(); }; class CView : public CWnd { DECLARE_DYNAMIC(CView) public: CView::CView() { } CView::~CView() { } }; // global function CWinApp* AfxGetApp();
//mfc.cpp
#include "my.h" CMyWinApp theApp; BOOL CMyWinApp::InitInstance() { m_pMainWnd = new CMyFrameWnd; return TRUE; } CMyFrameWnd::CMyFrameWnd() { Create(); } void PrintAllClasses() //输出“类别型录网“ { CRuntimeClass* pClass; //just walk through the simple list of registered classes for(pClass = CRuntimeClass::pFirstClass; pClass!=NULL; pClass = pClass->m_pNextClass) { cout<<pClass->m_lpszClassName<<"\n"; cout<<pClass->m_nObjectSize<<"\n"; cout<<pClass->m_wSchema<<"\n"; } } void main() { CWinApp* pApp = AfxGetApp(); pApp->InitApplication(); pApp->InitInstance(); pApp->Run(); PrintAllClasses(); }
//my.h
#include <iostream.h> #include "mfc.h" class CMyWinApp:public CWinApp { public: CMyWinApp::CMyWinApp(){} CMyWinApp::~CMyWinApp(){} virtual BOOL InitInstance(); }; class CMyFrameWnd:public CFrameWnd { public: CMyFrameWnd(); ~CMyFrameWnd(){} }; class CMyDoc:public CDocument { public: CMyDoc::CMyDoc(){} CMyDoc::~CMyDoc(){} }; class CMyView:public CView { public: CMyView::CMyView(){} CMyView::~CMyView(){} }; //global function void PrintAllClasses();
//my.cpp
#include "my.h" CMyWinApp theApp; BOOL CMyWinApp::InitInstance() { m_pMainWnd = new CMyFrameWnd; return TRUE; } CMyFrameWnd::CMyFrameWnd() { Create(); } void PrintAllClasses() //输出“类别型录网“ { CRuntimeClass* pClass; //just walk through the simple list of registered classes for(pClass = CRuntimeClass::pFirstClass; pClass!=NULL; pClass = pClass->m_pNextClass) { cout<<pClass->m_lpszClassName<<"\n"; cout<<pClass->m_nObjectSize<<"\n"; cout<<pClass->m_wSchema<<"\n"; } } void main() { CWinApp* pApp = AfxGetApp(); pApp->InitApplication(); pApp->InitInstance(); pApp->Run(); PrintAllClasses(); }
MFC中的运行时类型识别(RTTI)