最近因为正在读侯捷老师的深入浅出MFC第二版,看到RTTI时,觉得比较重要。作点学习笔记。
在VC++中,RTTI时依靠一种特殊的类型网来完成的。侯老师对这个建立“网”(其实可以当作一个链表来使用的)的过程进行了仿真。建立一个特殊的CRuntimeClass类,其中包含一个静态指针。类的生命代码如下:
struct CRuntimeClass
{
// Attributes
LPCSTR m_lpszClassName;
int m_nObjectSize;//Initialize with method sizeof(class_name)
UINT m_wSchema; // schema number of the loaded class
CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
CRuntimeClass* m_pBaseClass;//Point to it's father class
// CRuntimeClass objects linked together in simple list
CRuntimeClass* m_pNextClass; // linked list of registered classes
static CRuntimeClass* pFirstClass; // start of class list
};
该类可以记录一个类的父类(依靠指针m_pBaseClass),类的名称,大小和用于动态创建时所使用的创建函数,CObject*(PASCAL*m_pfnCreateObject)();
在编译的过程中,依靠CRuntimeClass的静态成员pFirstClass来建立一张已有的类的链表,链表中类的顺序与你在程序中指定的顺序相同。
在侯老师给出的示例程序中有两个宏是起关键性作用的。一个是DECLARE_DYNAMIC(class_name),另一个是IMPLEMENT_DYNAMIC,前者是用于在类中声明用于类型识别的类,而后者是用于把已有的类加入链表。
两个宏的定义如下:
#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)
其中宏_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 }; /
部分是用于对指定类的class##class_name作初始化,而 另一个部分则是为了把当前的类加入到类型识别的链表中。对于CObject作为表头,进行特殊的处理,不套用宏来完成加入链表的操作。
在建立链表后,就可以依靠运行时刻类CRuntimeClass的pFirstClass指针对要给定的类进行类型识别。
源代码如下:
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;//Initialize with method sizeof(class_name)
UINT m_wSchema; // schema number of the loaded class
CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
CRuntimeClass* m_pBaseClass;//Point to it's father class
// CRuntimeClass objects linked together in simple list
CRuntimeClass* m_pNextClass; // linked list of registered classes
static CRuntimeClass* pFirstClass; // start of class list
};
struct AFX_CLASSINIT
{
AFX_CLASSINIT(CRuntimeClass * pNewClass);
};
//Get the address of the member class##class_name of the class
#define RUNTIME_CLASS(class_name) /
(&class_name::class##class_name)
/*
*Declare two members in class_name.
* One is class##class_name : a static member which can stand for a type.
* Other is GetRuntimeClass()const used to get address of 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 CView : public CWnd
{
DECLARE_DYNAMIC(CView)
public:
CView::CView() {
}
CView::~CView() {
}
};
class CFrameWnd : public CWnd
{
DECLARE_DYNAMIC(CFrameWnd)
public:
CFrameWnd::CFrameWnd() {
}
CFrameWnd::~CFrameWnd() {
}
BOOL Create();
virtual BOOL PreCreateWindow();
};
// global function
CWinApp* AfxGetApp();
MFC.cpp-----------------------------------------------------------------------------------------------------------------------------
#include "my.h" // it should be mfc.h, but for CMyWinApp definition, so...
extern CMyWinApp theApp;
//3?ê??ˉCObjectμ?classCObject3é?±
static char szCObject[] = "CObject";
CRuntimeClass CObject::classCObject =
{szCObject , sizeof(CObject) ,0xffff , NULL , NULL , NULL} ;
static AFX_CLASSINIT _init_CObject(&CObject::classCObject);
CRuntimeClass* CRuntimeClass::pFirstClass = NULL;
//CRuntimeClassμ?pFirstClass????×üê????ò×?D??óè?μ?ò???àà
AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass * pNewClass){
pNewClass->m_pNextClass = CRuntimeClass::pFirstClass ;
CRuntimeClass::pFirstClass = pNewClass ;
}
CRuntimeClass * CObject::GetRuntimeClass()const {
return &CObject::classCObject ;
}
BOOL CWnd::Create()
{
return TRUE;
}
BOOL CWnd::CreateEx()
{
PreCreateWindow();
return TRUE;
}
BOOL CWnd::PreCreateWindow()
{
return TRUE;
}
BOOL CFrameWnd::Create()
{
CreateEx();
return TRUE;
}
BOOL CFrameWnd::PreCreateWindow()
{
return TRUE;
}
/**
* ???ùóDμ?àà3é?±±?á?class##class_name??DD3?ê??ˉ
*/
IMPLEMENT_DYNAMIC(CCmdTarget , CObject)
IMPLEMENT_DYNAMIC(CWinThread , CCmdTarget)
IMPLEMENT_DYNAMIC(CWinApp , CWinThread)
IMPLEMENT_DYNAMIC(CWnd , CCmdTarget)
IMPLEMENT_DYNAMIC(CFrameWnd , CWnd)
IMPLEMENT_DYNAMIC(CDocument , CCmdTarget)
IMPLEMENT_DYNAMIC(CView , CWnd)
CWinApp* AfxGetApp()
{
return theApp.m_pCurrentWinApp;
}
MY.h--------------------------------------------------------------------------------------
#include <iostream.h>
#include "mfc.h"
class CMyWinApp : public CWinApp
{
DECLARE_DYNAMIC(CMyWinApp)
public:
CMyWinApp::CMyWinApp() {
}
CMyWinApp::~CMyWinApp() {
}
virtual BOOL InitInstance();
};
class CMyFrameWnd : public CFrameWnd
{
DECLARE_DYNAMIC(CMyFrameWnd)
public:
CMyFrameWnd();
~CMyFrameWnd() {
}
};
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 ;
for(pClass=CRuntimeClass::pFirstClass ; pClass!=NULL ; pClass=pClass->m_pNextClass){
cout<<pClass->m_lpszClassName<<endl ;
cout<<pClass->m_nObjectSize<<endl;
cout<<pClass->m_wSchema<<endl<<endl;
}
}
IMPLEMENT_DYNAMIC(CMyWinApp , CWinApp)
IMPLEMENT_DYNAMIC(CMyFrameWnd , CFrameWnd)
//------------------------------------------------------------------
// main
//------------------------------------------------------------------
void main()
{
CWinApp* pApp = AfxGetApp();
pApp->InitApplication();
pApp->InitInstance();
pApp->Run();
PrintAllClasses();
}
//------------------------------------------------------------------
在VC++中,RTTI时依靠一种特殊的类型网来完成的。侯老师对这个建立“网”(其实可以当作一个链表来使用的)的过程进行了仿真。建立一个特殊的CRuntimeClass类,其中包含一个静态指针。类的生命代码如下:
struct CRuntimeClass
{
// Attributes
LPCSTR m_lpszClassName;
int m_nObjectSize;//Initialize with method sizeof(class_name)
UINT m_wSchema; // schema number of the loaded class
CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
CRuntimeClass* m_pBaseClass;//Point to it's father class
// CRuntimeClass objects linked together in simple list
CRuntimeClass* m_pNextClass; // linked list of registered classes
static CRuntimeClass* pFirstClass; // start of class list
};
该类可以记录一个类的父类(依靠指针m_pBaseClass),类的名称,大小和用于动态创建时所使用的创建函数,CObject*(PASCAL*m_pfnCreateObject)();
在编译的过程中,依靠CRuntimeClass的静态成员pFirstClass来建立一张已有的类的链表,链表中类的顺序与你在程序中指定的顺序相同。
在侯老师给出的示例程序中有两个宏是起关键性作用的。一个是DECLARE_DYNAMIC(class_name),另一个是IMPLEMENT_DYNAMIC,前者是用于在类中声明用于类型识别的类,而后者是用于把已有的类加入链表。
两个宏的定义如下:
#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)
其中宏_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 }; /
部分是用于对指定类的class##class_name作初始化,而 另一个部分则是为了把当前的类加入到类型识别的链表中。对于CObject作为表头,进行特殊的处理,不套用宏来完成加入链表的操作。
在建立链表后,就可以依靠运行时刻类CRuntimeClass的pFirstClass指针对要给定的类进行类型识别。
源代码如下:
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;//Initialize with method sizeof(class_name)
UINT m_wSchema; // schema number of the loaded class
CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
CRuntimeClass* m_pBaseClass;//Point to it's father class
// CRuntimeClass objects linked together in simple list
CRuntimeClass* m_pNextClass; // linked list of registered classes
static CRuntimeClass* pFirstClass; // start of class list
};
struct AFX_CLASSINIT
{
AFX_CLASSINIT(CRuntimeClass * pNewClass);
};
//Get the address of the member class##class_name of the class
#define RUNTIME_CLASS(class_name) /
(&class_name::class##class_name)
/*
*Declare two members in class_name.
* One is class##class_name : a static member which can stand for a type.
* Other is GetRuntimeClass()const used to get address of 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 CView : public CWnd
{
DECLARE_DYNAMIC(CView)
public:
CView::CView() {
}
CView::~CView() {
}
};
class CFrameWnd : public CWnd
{
DECLARE_DYNAMIC(CFrameWnd)
public:
CFrameWnd::CFrameWnd() {
}
CFrameWnd::~CFrameWnd() {
}
BOOL Create();
virtual BOOL PreCreateWindow();
};
// global function
CWinApp* AfxGetApp();
MFC.cpp-----------------------------------------------------------------------------------------------------------------------------
#include "my.h" // it should be mfc.h, but for CMyWinApp definition, so...
extern CMyWinApp theApp;
//3?ê??ˉCObjectμ?classCObject3é?±
static char szCObject[] = "CObject";
CRuntimeClass CObject::classCObject =
{szCObject , sizeof(CObject) ,0xffff , NULL , NULL , NULL} ;
static AFX_CLASSINIT _init_CObject(&CObject::classCObject);
CRuntimeClass* CRuntimeClass::pFirstClass = NULL;
//CRuntimeClassμ?pFirstClass????×üê????ò×?D??óè?μ?ò???àà
AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass * pNewClass){
pNewClass->m_pNextClass = CRuntimeClass::pFirstClass ;
CRuntimeClass::pFirstClass = pNewClass ;
}
CRuntimeClass * CObject::GetRuntimeClass()const {
return &CObject::classCObject ;
}
BOOL CWnd::Create()
{
return TRUE;
}
BOOL CWnd::CreateEx()
{
PreCreateWindow();
return TRUE;
}
BOOL CWnd::PreCreateWindow()
{
return TRUE;
}
BOOL CFrameWnd::Create()
{
CreateEx();
return TRUE;
}
BOOL CFrameWnd::PreCreateWindow()
{
return TRUE;
}
/**
* ???ùóDμ?àà3é?±±?á?class##class_name??DD3?ê??ˉ
*/
IMPLEMENT_DYNAMIC(CCmdTarget , CObject)
IMPLEMENT_DYNAMIC(CWinThread , CCmdTarget)
IMPLEMENT_DYNAMIC(CWinApp , CWinThread)
IMPLEMENT_DYNAMIC(CWnd , CCmdTarget)
IMPLEMENT_DYNAMIC(CFrameWnd , CWnd)
IMPLEMENT_DYNAMIC(CDocument , CCmdTarget)
IMPLEMENT_DYNAMIC(CView , CWnd)
CWinApp* AfxGetApp()
{
return theApp.m_pCurrentWinApp;
}
MY.h--------------------------------------------------------------------------------------
#include <iostream.h>
#include "mfc.h"
class CMyWinApp : public CWinApp
{
DECLARE_DYNAMIC(CMyWinApp)
public:
CMyWinApp::CMyWinApp() {
}
CMyWinApp::~CMyWinApp() {
}
virtual BOOL InitInstance();
};
class CMyFrameWnd : public CFrameWnd
{
DECLARE_DYNAMIC(CMyFrameWnd)
public:
CMyFrameWnd();
~CMyFrameWnd() {
}
};
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 ;
for(pClass=CRuntimeClass::pFirstClass ; pClass!=NULL ; pClass=pClass->m_pNextClass){
cout<<pClass->m_lpszClassName<<endl ;
cout<<pClass->m_nObjectSize<<endl;
cout<<pClass->m_wSchema<<endl<<endl;
}
}
IMPLEMENT_DYNAMIC(CMyWinApp , CWinApp)
IMPLEMENT_DYNAMIC(CMyFrameWnd , CFrameWnd)
//------------------------------------------------------------------
// main
//------------------------------------------------------------------
void main()
{
CWinApp* pApp = AfxGetApp();
pApp->InitApplication();
pApp->InitInstance();
pApp->Run();
PrintAllClasses();
}
//------------------------------------------------------------------