当前位置: 代码迷 >> 综合 >> MFC中的运行时类型识别(RTTI)
  详细解决方案

MFC中的运行时类型识别(RTTI)

热度:20   发布时间:2023-12-21 07:33:56.0

      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)


于是,组织出如图(3-1)所示的一张大网:


       为了证明,程序中存在整个“类别型录网。我在main函数中调用 PrintAllClasses ,把链表中的每一个元素的类名称、对象大小,以及scheme.no,打印出来。

void PrintAllClasses() //输出“类别型录网“
{CRuntimeClass* pClass;//just walk through the simple list of registered classesfor(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
{
// AttributesLPCSTR m_lpszClassName;int m_nObjectSize;UINT m_wSchema; // schema number of the loaded classCObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract classCRuntimeClass* m_pBaseClass;// CRuntimeClass objects linked together in simple liststatic CRuntimeClass* pFirstClass; // start of class listCRuntimeClass* 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 classesfor(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 classesfor(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();
}