深入浅出MFC学习笔记:(第三章MFC六大关键技术之仿真:类型识别,动态创建) .
2014-06-27 10:55
232 查看
第三章:MFC六大关键技术之仿真:类型识别
深入理解MFC的内部运行原理,是本次学习《深入浅出MFC》的主要目的。要模仿的六大技术包括:
1:MFC程序的初始化过程。
2:RTTI(Runtime type identification)运行时类型识别。
3:Dynamic creation 动态创建
4:Persistence永久保存
5:消息映射
6:消息传递。
RTTI(运行时类型识别)
IsKindOf能够侦测某个对象是否属于某种类。即判断某一对象所属的类是否是父类或当前类;
要达到动态类型识别的能力,必须在构建类继承体系时记录必要的信息,这被称为类型型录表。MFC以链表的方式建立了此表。
类型型录表的每个元素为CRuntimeClass类型,其定义为:
[cpp] view
plaincopy
class CRuntimeClass
{
public:
LPCSTR m_lpszClassName;//对象所属类名
Int m_nObjectSize;//对象大小
UINT m_wSchema;//模式号
CObject *(PASCAL*m_pfnCreateObject)();//构建函数抽象类为NULL
CRuntimeClass *pBaseClasss;//基类CRuntimeClass对象指针。
Static CRuntimeClass *pFirstClass;//链表头指针。
CRuntimeClass *m_pNextClass;//下一指针。
};
MFC使用此类作为每个类的成员变量。使用宏定义为每个类定义了自己的CRuntimeClass成员变量。
DECLAR_DYNAMIC和IMPLENMENT_DYNAMIC宏
使用这两个宏将CRuntimeClass对象不知不觉放到类之中。
DECLARE_DYNMIC宏定义如下:
[cpp] view
plaincopy
#define DELCARE_DYNMIC ( class_name ) \
public:\
static CRuntimeClass class##class_name \
virtual CRuntimeClass *GetRuntimeClass()const;
##用来告诉编译器把两个字符串连接起来。
如果使用这个宏:DELCARE_DYNMIC(CView);
那么预编译器将生成下列代码:
[cpp] view
plaincopy
public:
static CRuntimeClass classCView;
virtual CRuntimeClass*GetRuntimeClass()const;
以上代码仅仅是在类中定义CRuntimeClass对象,并定义一个返回CRuntimeClass对象地址的函数。注意CRuntimeClass是static的,也就是说同一种类继承体系的对象共享一个CRuntimeClass对象。
初始化对象的内容以及建立类型型录表需要使用IMPLEMENT_DYNMIC宏。
[cpp] view
plaincopy
#define IMPLEMENT_DYNMIC (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##classname;\
}
#define RUNTIME_CLASS(class_name)\
( &class_name::class##class_name);
AFX_CLASSINIT是一个类,看着跟宏定义似的,这样做很容易让人迷惑。它用于将本节点连接到类型型录表,定义如下:
[cpp] view
plaincopy
class AFX_CLASSINIT
{
public:
AFX_CLASSINIT(CRuntimeClass*pNewClass)//构造函数
{
pNewClass->m_pNextClass=CRuntime::pFirstClass;
CRuntimeClass::pFirstClass =pNewClass;
}
};
用法:
[cpp] view
plaincopy
class CWnd:public CCmdTarget
{
public:
DECLARE_DYNAMIC(CWnd);
};
IMPLEMENT_DYNMIC(CWnd,CCmdTarget);
代码展开后为;
[cpp] view
plaincopy
class CWnd:public CCmdTarget
{
public:
static CRuntimeClass classCView;
virtual CRuntimeClass*GetRuntimeClass()const
};
static char _lpszCWnd[]="CWnd";
CRuntimeClass CWnd::classCWnd=
{
_lpszCView , sizeof(CWnd) , FFFF,NULL , &Wnd::classCWnd , NULL);
};
static AFX_CLASSINIT _init_CWnd(&CWnd::classCWnd);
{
Return &CWnd::classCWnd;
}
定义宏的过程很复杂,但是一旦定义好之后,在使用时仅仅两句话就可以完成定义CRuntimeClass对象并且连接类型型录链表的工作。
CObject是所有类的基类,也是链表的头,此类应特别定义,不能在CObject内使用定义好的宏。
[cpp] view
plaincopy
class CObject
{
public:
virtual CRuntimeClass*GetRuntimeClass()const;
static CRuntimeClass classCObject;
};
static char szCobject[]="CObject";
struct CRuntimeClass CObject::classCObject=
{
szCObject ,sizeof(CObject),0xFFFF,NULL,NULL,NULL
};
static AFX_CLASSINIT _init_CObject(&Cobject::classObject);
CRuntimeClass *CObject::GetRuntimeClass()const
{
return &CObject::classCObject;
}
由于CRuntimeClass对象是static成员变量,因此需要在类外初始化。如果忘记初始化将会报链接错误。
CRuntimeClass*CRuntimeClass::pFirstClass=NULL;
建好了类类型路表,要实现IsKindOf功能很容易。首先在CObject加上一个IsKindOf函数,于是所有继承自此类的类都具有类型识别的功能。能够将某个CRuntimeClass对象与类类型型录中的元素进行比较。如:
[cpp] view
plaincopy
class CObject
{
public:
bool IsKindOf(const CRuntimeClass*pClass)const
{
CRuntimeClass *pClassThis=GetRuntimeClass();
while(pClassThis)
{
if(pClassThis==pClass)
return true;
pClassThis=pClassThis->m_pBaseClass;//沿着基类寻找。
}
return false;
}
};
如果我们调用CWnd *cw=new CWnd;
cw->IsKindOf(RUNTIME_CLASS(CFrameWnd));
RUNTIME_CLASS实际就是&CFrameWnd::classCFrameWnd,它就是CFrameWnd的static的CRuntimeClass类型成员。函数内利用GetRuntimeClass取得本类的CRuntimeClass对象的地址,即&CWnd::classCWnd,然后进行比较。因为每一类型共用一个static的CRuntimeClass对象,因此属于同于类的CRuntimeClass对象的地址相同。
动态创建
每一类的构建函数可以记录在类型别录中,当获得一个类名称,通过查找类别型录表找出对应的元素,然后调用其构建函数产生新对象。
在CRuntimeClass中m_pfnCreateObject即为构建函数首地址。
为了实现动态创建,需要添加两个宏:
DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE。
如:
[cpp] view
plaincopy
#define DECLARE_DYNCREATE(class_name)\
DECLARE_DYNCREATE(class_name)\
static CObject *PASCAL CreateObject();
#define IMPLEMENT_DYNCREATE (class_name,base_class_name)\
CObject*PASCAL class_name::CreateObject()\
{return new classname;};\
_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,
0xFFFF,class_name::CreateObject)
以CFrameWnd为例,下列程序代码:
[cpp] view
plaincopy
class CFrameWnd:public CWnd
{
public:
DECLEARE_DYNCREATE(CFrameWnd);
};
IMPLEMENT_DYNCREATE(CFrameWnd,CWnd);
展开如下:
[cpp] view
plaincopy
class CFrame:public CWnd
{
public:
static CRuntimeClass classCFrameWnd;
virtual CRuntimeClass *GetRuntimeClass()const;
static CObject *PASCAL CreateObject();
};
CObject _PASCAL CFrameWnd::CreateObject()
{
return new CFrameWnd;
}
static char _lpszCFrameWnd[]="CFrameWnd";
CRuntimeClass CFrameClass::classCFrameWnd={
_lpszCFrameWnd,sizeof(CFrameWnd),0xFFFF,CFrameWnd::CreateObject,RUNTIME_CALSS(CWnd),NULL};
static AFX_CLASSINIT _init_CFrameWnd
(&CFrameWnd::classCFrameWnd);
CRuntimeClass*CFrameWnd::GetRunimeClass()const
{return &CFrameWnd::classCFrameWnd;}
注意对象构建函数为static函数。
为了支持动态创建需要在CRuntimeClass内添加两个函数:CreateObject和CRuntimeClass::Load成员函数。
[cpp] view
plaincopy
CObject *CRuntimeClass::CreateObject()
{
If(m_pfnCreateObject==NULL)//不支持动态创建。
{
throw runtime_error("此类不支持动态创建");
Return NULL;
}
CObject*pObject=(*m_pfnCreateObject)();
Return pObject;
}
CRuntimeClass*PASCL CRuntimeClass::Load()
{
Char szClassName[64];
CRuntimeClass*pClass
cout<<"输入一个类名:";
cin>>szClassName;
for(pClass=pFirstClass;pClass;pClass=pClass->m_pNextClass)
{
if(strcmp(szClassName,pClass->m_lpszClassName)==0)
return pClass;
return NULL;
}
}
以下为类型识别及动态创建的完整代码:
[cpp] view
plaincopy
<span style="font-size:18px;">#include<iostream>
#include<windows.h>
#include<string>
using namespace std;
class CObject;
class CRuntimeClass
{
public:
char* m_lpszClassName;//对象所属类名
int m_nObjectSize;//对象大小
int m_wSchema;//模式号
CObject*(PASCAL*m_pfnCreateObject)();//构建函数,抽象类为NULL
CRuntimeClass *m_pBaseClasss;//基类CRuntimeClass对象指针。
static CRuntimeClass *pFirstClass;//链表头指针。static
CRuntimeClass *m_pNextClass;//下一指针。
public:
CObject*CreateObject()
{
if(m_pfnCreateObject==NULL)
{
cout<<"该类型不支持动态创建!!"<<endl;
return NULL;
}
CObject*pClass=(*m_pfnCreateObject)();
return pClass;
}
static CRuntimeClass*Load()
{
cout<<"请输入要动态创建的类名:";
string s;
cin>>s;
for(CRuntimeClass*pClass=pFirstClass;pClass;pClass=pClass->m_pBaseClasss)
{
if(pClass->m_lpszClassName==s)
{
return pClass;
}
}
return NULL;
}
};
class AFX_CLASSINIT
{
public:
AFX_CLASSINIT(CRuntimeClass*pNewClass)//构造函数
{
pNewClass->m_pNextClass=CRuntimeClass::pFirstClass;
CRuntimeClass::pFirstClass =pNewClass;
}
};
/************************************************************************/
/* 动态类型识别宏定义
//与CRuntimeClass类中的构建函数相区别。此处的CreateObject函数在每个类中都以static成员函数存在,用以
//初始化类型型录表,而CRuntimeClass中的CreateObject用于调用每个类的构建函数。仅仅是函数名相同罢了。*/
/************************************************************************/
#define DECLARE_DYNAMIC(class_name)\
public:\
static CRuntimeClass Class##class_name;\
virtual CRuntimeClass*GetRuntimeClass()const;\
#define DECLARE_DYNCREATE(class_name)\
DECLARE_DYNAMIC(class_name)\
static CObject*PASCAL CreateObject();\
#define RUNTIME_CLASS(class_name)\
(&class_name::Class##class_name)\
#define _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,wSchema,pfnNew)\
class CRuntimeClass class_name::Class##class_name ={\
#class_name,\
sizeof(class_name),wSchema,pfnNew,RUNTIME_CLASS(base_class_name),NULL};\
static AFX_CLASSINIT _init##class_name( RUNTIME_CLASS(class_name));\
CRuntimeClass *class_name::GetRuntimeClass()const\
{return &class_name::Class##class_name;}//此处将class_name写成了classname花了一两天才查出来。啊啊啊啊啊。20120605
#define IMPLEMENT_DYNAMIC(class_name,base_class_name)\
_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NULL)\
#define IMPLEMENT_DYNCREATE(class_name,base_class_name)\
CObject*PASCAL class_name::CreateObject(){return new class_name;}\
_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,class_name::CreateObject)\
/************************************************************************/
/* 对CObject特殊处理。 */
/************************************************************************/
class CObject
{
public:
CObject()
{
//cout<<"CObject constructor!"<<endl;
}
~CObject()
{
//cout<<"CObject destructor!"<<endl;
}
public:
virtual CRuntimeClass*GetRuntimeClass();
static CRuntimeClass ClassCObject;
public:
bool IsKindOf(CRuntimeClass*pClass)
{
CRuntimeClass *pThis=GetRuntimeClass();
for(;pThis;pThis=pThis->m_pBaseClasss)
{
if(pThis==pClass)
{
return true;
}
}
return false;
}
};
class CRuntimeClass CObject:: ClassCObject=
{
"CObject",sizeof(CObject),0xFFFF,NULL,NULL,NULL
};
static AFX_CLASSINIT _init_CObject(&CObject:: ClassCObject);
CRuntimeClass *CObject::GetRuntimeClass()
{
return &CObject::ClassCObject;
}
CRuntimeClass*CRuntimeClass::pFirstClass=NULL;
/************************************************************************/
/* */
/************************************************************************/
class CCmdTarget:public CObject
{
DECLARE_DYNCREATE(CCmdTarget)
public:
CCmdTarget()
{
//cout<<"CCmdTarget constructor!"<<endl;
//CreateObject();
}
~CCmdTarget()
{
//cout<<"CCmdTarget destructor!"<<endl;
}
};
IMPLEMENT_DYNCREATE(CCmdTarget,CObject)
;
class CWnd:public CCmdTarget
{
DECLARE_DYNCREATE(CWnd)
public:
CWnd()
{
//cout<<"CWnd constructor"<<endl;
}
~CWnd()
{
//cout<<"CWnd destructor"<<endl;
}
public:
virtual bool Create()
{
cout<<"CWnd::Create"<<endl;
CreateEx();
return true;
}
bool CreateEx()
{
cout<<"CWnd::CreateEx"<<endl;
PreCreateWindow();
return true;
}
virtual bool PreCreateWindow()
{
cout<<"CWnd::PreCreateWindow"<<endl;
return true;
}
};
IMPLEMENT_DYNCREATE(CWnd,CCmdTarget)
class CView :public CWnd
{
DECLARE_DYNCREATE(CView)
public:
CView()
{
//cout<<"CView constructor"<<endl;
}
~CView()
{
//cout<<"CView destructor"<<endl;
}
};
IMPLEMENT_DYNCREATE(CView,CWnd)
class CFrameWnd:public CWnd
{
DECLARE_DYNCREATE(CFrameWnd)
public:
CFrameWnd()
{
//cout<<"CFrameWnd constructor"<<endl;
}
~CFrameWnd()
{
//cout<<"CFrameWnd destructor"<<endl;
}
public:
virtual bool Create()
{
cout<<"CFrameWnd::Create"<<endl;
CreateEx();
return true;
}
virtual bool PreCreateWindow()
{
cout<<"CFrameWnd::PreCreateWindow"<<endl;
return true;
}
};
IMPLEMENT_DYNCREATE(CFrameWnd,CWnd)
class CWinThread:public CCmdTarget
{
public:
CWinThread()
{
//cout<<"CWinThread constructor"<<endl;
}
~CWinThread()
{
//cout<<"CWinThread destructor"<<endl;
}
public:
virtual bool InitInstance()
{
cout<<"CWinThread::InitInstance"<<endl;
return true;
}
virtual bool Run()
{
cout<<"CWinThread::Run"<<endl;
return true;
}
};
class CWinApp:public CWinThread
{
public:
CWinApp()
{
//cout<<"CWinApp Constructor "<<endl;
m_currentApp=this;
}
~CWinApp()
{
//cout<<"CWinApp destructor "<<endl;
}
virtual bool InitApplication()
{
cout<<"CWinApp::InitApplication"<<endl;
return true;
}
virtual bool InitInstance()
{
cout<<"CWinApp:InitInstance"<<endl;
return true;
}
virtual bool Run()
{
cout<<"CWinApp::Run"<<endl;
return CWinThread::Run();
}
public:
CWinApp*m_currentApp;
CFrameWnd*m_currentFrameWnd;
};
class CDocument:public CCmdTarget
{
public:
CDocument()
{
//cout<<"CDocument constructor "<<endl;
}
~CDocument()
{
//cout<<"CDocunment destructor "<<endl;
}
};
class CMyFrameWnd:public CFrameWnd
{
DECLARE_DYNCREATE(CMyFrameWnd)
public:
CMyFrameWnd()
{
//cout<<"CMyFrameWnd constructor "<<endl;
Create();
}
~CMyFrameWnd()
{
//cout<<"CMyFrameWnd destructor "<<endl;
}
};
IMPLEMENT_DYNCREATE(CMyFrameWnd,CFrameWnd)
class CMyWinApp:public CWinApp
{
public:
CMyWinApp()
{
//cout<<"CMyWinApp constructor "<<endl;
}
~CMyWinApp()
{
//cout<<"CMyWinApp destructor "<<endl;
}
public:
bool InitInstance()
{
cout<<"CMyWinApp::InitInstance"<<endl;
m_currentFrameWnd=new CMyFrameWnd;
return true;
}
};
CMyWinApp myApp;
CWinApp*AfxGetApp()
{
return myApp.m_currentApp;
}
int main(int argc,char**argv)
{
CWinApp *pApp=AfxGetApp();
pApp->InitApplication();
pApp->InitInstance();
pApp->Run();
CRuntimeClass *pClass;
CObject *pOb;
cout<<"以下为类型型录链表中的所有类的名称:"<<endl;
for(pClass=CRuntimeClass::pFirstClass;pClass;pClass=pClass->m_pBaseClasss)
{
cout<<pClass->m_lpszClassName<<endl;
}
while(1)
{
pClass=CRuntimeClass::Load();
if(!pClass)
{
cout<<"找不到此类!!!"<<endl;
}
else
{
pOb=pClass->CreateObject();
if(pOb)
{
cout<<"创建成功!"<<endl;
}
}
}
return 0;
}</span>
深入理解MFC的内部运行原理,是本次学习《深入浅出MFC》的主要目的。要模仿的六大技术包括:
1:MFC程序的初始化过程。
2:RTTI(Runtime type identification)运行时类型识别。
3:Dynamic creation 动态创建
4:Persistence永久保存
5:消息映射
6:消息传递。
RTTI(运行时类型识别)
IsKindOf能够侦测某个对象是否属于某种类。即判断某一对象所属的类是否是父类或当前类;
要达到动态类型识别的能力,必须在构建类继承体系时记录必要的信息,这被称为类型型录表。MFC以链表的方式建立了此表。
类型型录表的每个元素为CRuntimeClass类型,其定义为:
[cpp] view
plaincopy
class CRuntimeClass
{
public:
LPCSTR m_lpszClassName;//对象所属类名
Int m_nObjectSize;//对象大小
UINT m_wSchema;//模式号
CObject *(PASCAL*m_pfnCreateObject)();//构建函数抽象类为NULL
CRuntimeClass *pBaseClasss;//基类CRuntimeClass对象指针。
Static CRuntimeClass *pFirstClass;//链表头指针。
CRuntimeClass *m_pNextClass;//下一指针。
};
MFC使用此类作为每个类的成员变量。使用宏定义为每个类定义了自己的CRuntimeClass成员变量。
DECLAR_DYNAMIC和IMPLENMENT_DYNAMIC宏
使用这两个宏将CRuntimeClass对象不知不觉放到类之中。
DECLARE_DYNMIC宏定义如下:
[cpp] view
plaincopy
#define DELCARE_DYNMIC ( class_name ) \
public:\
static CRuntimeClass class##class_name \
virtual CRuntimeClass *GetRuntimeClass()const;
##用来告诉编译器把两个字符串连接起来。
如果使用这个宏:DELCARE_DYNMIC(CView);
那么预编译器将生成下列代码:
[cpp] view
plaincopy
public:
static CRuntimeClass classCView;
virtual CRuntimeClass*GetRuntimeClass()const;
以上代码仅仅是在类中定义CRuntimeClass对象,并定义一个返回CRuntimeClass对象地址的函数。注意CRuntimeClass是static的,也就是说同一种类继承体系的对象共享一个CRuntimeClass对象。
初始化对象的内容以及建立类型型录表需要使用IMPLEMENT_DYNMIC宏。
[cpp] view
plaincopy
#define IMPLEMENT_DYNMIC (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##classname;\
}
#define RUNTIME_CLASS(class_name)\
( &class_name::class##class_name);
AFX_CLASSINIT是一个类,看着跟宏定义似的,这样做很容易让人迷惑。它用于将本节点连接到类型型录表,定义如下:
[cpp] view
plaincopy
class AFX_CLASSINIT
{
public:
AFX_CLASSINIT(CRuntimeClass*pNewClass)//构造函数
{
pNewClass->m_pNextClass=CRuntime::pFirstClass;
CRuntimeClass::pFirstClass =pNewClass;
}
};
用法:
[cpp] view
plaincopy
class CWnd:public CCmdTarget
{
public:
DECLARE_DYNAMIC(CWnd);
};
IMPLEMENT_DYNMIC(CWnd,CCmdTarget);
代码展开后为;
[cpp] view
plaincopy
class CWnd:public CCmdTarget
{
public:
static CRuntimeClass classCView;
virtual CRuntimeClass*GetRuntimeClass()const
};
static char _lpszCWnd[]="CWnd";
CRuntimeClass CWnd::classCWnd=
{
_lpszCView , sizeof(CWnd) , FFFF,NULL , &Wnd::classCWnd , NULL);
};
static AFX_CLASSINIT _init_CWnd(&CWnd::classCWnd);
{
Return &CWnd::classCWnd;
}
定义宏的过程很复杂,但是一旦定义好之后,在使用时仅仅两句话就可以完成定义CRuntimeClass对象并且连接类型型录链表的工作。
CObject是所有类的基类,也是链表的头,此类应特别定义,不能在CObject内使用定义好的宏。
[cpp] view
plaincopy
class CObject
{
public:
virtual CRuntimeClass*GetRuntimeClass()const;
static CRuntimeClass classCObject;
};
static char szCobject[]="CObject";
struct CRuntimeClass CObject::classCObject=
{
szCObject ,sizeof(CObject),0xFFFF,NULL,NULL,NULL
};
static AFX_CLASSINIT _init_CObject(&Cobject::classObject);
CRuntimeClass *CObject::GetRuntimeClass()const
{
return &CObject::classCObject;
}
由于CRuntimeClass对象是static成员变量,因此需要在类外初始化。如果忘记初始化将会报链接错误。
CRuntimeClass*CRuntimeClass::pFirstClass=NULL;
建好了类类型路表,要实现IsKindOf功能很容易。首先在CObject加上一个IsKindOf函数,于是所有继承自此类的类都具有类型识别的功能。能够将某个CRuntimeClass对象与类类型型录中的元素进行比较。如:
[cpp] view
plaincopy
class CObject
{
public:
bool IsKindOf(const CRuntimeClass*pClass)const
{
CRuntimeClass *pClassThis=GetRuntimeClass();
while(pClassThis)
{
if(pClassThis==pClass)
return true;
pClassThis=pClassThis->m_pBaseClass;//沿着基类寻找。
}
return false;
}
};
如果我们调用CWnd *cw=new CWnd;
cw->IsKindOf(RUNTIME_CLASS(CFrameWnd));
RUNTIME_CLASS实际就是&CFrameWnd::classCFrameWnd,它就是CFrameWnd的static的CRuntimeClass类型成员。函数内利用GetRuntimeClass取得本类的CRuntimeClass对象的地址,即&CWnd::classCWnd,然后进行比较。因为每一类型共用一个static的CRuntimeClass对象,因此属于同于类的CRuntimeClass对象的地址相同。
动态创建
每一类的构建函数可以记录在类型别录中,当获得一个类名称,通过查找类别型录表找出对应的元素,然后调用其构建函数产生新对象。
在CRuntimeClass中m_pfnCreateObject即为构建函数首地址。
为了实现动态创建,需要添加两个宏:
DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE。
如:
[cpp] view
plaincopy
#define DECLARE_DYNCREATE(class_name)\
DECLARE_DYNCREATE(class_name)\
static CObject *PASCAL CreateObject();
#define IMPLEMENT_DYNCREATE (class_name,base_class_name)\
CObject*PASCAL class_name::CreateObject()\
{return new classname;};\
_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,
0xFFFF,class_name::CreateObject)
以CFrameWnd为例,下列程序代码:
[cpp] view
plaincopy
class CFrameWnd:public CWnd
{
public:
DECLEARE_DYNCREATE(CFrameWnd);
};
IMPLEMENT_DYNCREATE(CFrameWnd,CWnd);
展开如下:
[cpp] view
plaincopy
class CFrame:public CWnd
{
public:
static CRuntimeClass classCFrameWnd;
virtual CRuntimeClass *GetRuntimeClass()const;
static CObject *PASCAL CreateObject();
};
CObject _PASCAL CFrameWnd::CreateObject()
{
return new CFrameWnd;
}
static char _lpszCFrameWnd[]="CFrameWnd";
CRuntimeClass CFrameClass::classCFrameWnd={
_lpszCFrameWnd,sizeof(CFrameWnd),0xFFFF,CFrameWnd::CreateObject,RUNTIME_CALSS(CWnd),NULL};
static AFX_CLASSINIT _init_CFrameWnd
(&CFrameWnd::classCFrameWnd);
CRuntimeClass*CFrameWnd::GetRunimeClass()const
{return &CFrameWnd::classCFrameWnd;}
注意对象构建函数为static函数。
为了支持动态创建需要在CRuntimeClass内添加两个函数:CreateObject和CRuntimeClass::Load成员函数。
[cpp] view
plaincopy
CObject *CRuntimeClass::CreateObject()
{
If(m_pfnCreateObject==NULL)//不支持动态创建。
{
throw runtime_error("此类不支持动态创建");
Return NULL;
}
CObject*pObject=(*m_pfnCreateObject)();
Return pObject;
}
CRuntimeClass*PASCL CRuntimeClass::Load()
{
Char szClassName[64];
CRuntimeClass*pClass
cout<<"输入一个类名:";
cin>>szClassName;
for(pClass=pFirstClass;pClass;pClass=pClass->m_pNextClass)
{
if(strcmp(szClassName,pClass->m_lpszClassName)==0)
return pClass;
return NULL;
}
}
以下为类型识别及动态创建的完整代码:
[cpp] view
plaincopy
<span style="font-size:18px;">#include<iostream>
#include<windows.h>
#include<string>
using namespace std;
class CObject;
class CRuntimeClass
{
public:
char* m_lpszClassName;//对象所属类名
int m_nObjectSize;//对象大小
int m_wSchema;//模式号
CObject*(PASCAL*m_pfnCreateObject)();//构建函数,抽象类为NULL
CRuntimeClass *m_pBaseClasss;//基类CRuntimeClass对象指针。
static CRuntimeClass *pFirstClass;//链表头指针。static
CRuntimeClass *m_pNextClass;//下一指针。
public:
CObject*CreateObject()
{
if(m_pfnCreateObject==NULL)
{
cout<<"该类型不支持动态创建!!"<<endl;
return NULL;
}
CObject*pClass=(*m_pfnCreateObject)();
return pClass;
}
static CRuntimeClass*Load()
{
cout<<"请输入要动态创建的类名:";
string s;
cin>>s;
for(CRuntimeClass*pClass=pFirstClass;pClass;pClass=pClass->m_pBaseClasss)
{
if(pClass->m_lpszClassName==s)
{
return pClass;
}
}
return NULL;
}
};
class AFX_CLASSINIT
{
public:
AFX_CLASSINIT(CRuntimeClass*pNewClass)//构造函数
{
pNewClass->m_pNextClass=CRuntimeClass::pFirstClass;
CRuntimeClass::pFirstClass =pNewClass;
}
};
/************************************************************************/
/* 动态类型识别宏定义
//与CRuntimeClass类中的构建函数相区别。此处的CreateObject函数在每个类中都以static成员函数存在,用以
//初始化类型型录表,而CRuntimeClass中的CreateObject用于调用每个类的构建函数。仅仅是函数名相同罢了。*/
/************************************************************************/
#define DECLARE_DYNAMIC(class_name)\
public:\
static CRuntimeClass Class##class_name;\
virtual CRuntimeClass*GetRuntimeClass()const;\
#define DECLARE_DYNCREATE(class_name)\
DECLARE_DYNAMIC(class_name)\
static CObject*PASCAL CreateObject();\
#define RUNTIME_CLASS(class_name)\
(&class_name::Class##class_name)\
#define _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,wSchema,pfnNew)\
class CRuntimeClass class_name::Class##class_name ={\
#class_name,\
sizeof(class_name),wSchema,pfnNew,RUNTIME_CLASS(base_class_name),NULL};\
static AFX_CLASSINIT _init##class_name( RUNTIME_CLASS(class_name));\
CRuntimeClass *class_name::GetRuntimeClass()const\
{return &class_name::Class##class_name;}//此处将class_name写成了classname花了一两天才查出来。啊啊啊啊啊。20120605
#define IMPLEMENT_DYNAMIC(class_name,base_class_name)\
_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NULL)\
#define IMPLEMENT_DYNCREATE(class_name,base_class_name)\
CObject*PASCAL class_name::CreateObject(){return new class_name;}\
_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,class_name::CreateObject)\
/************************************************************************/
/* 对CObject特殊处理。 */
/************************************************************************/
class CObject
{
public:
CObject()
{
//cout<<"CObject constructor!"<<endl;
}
~CObject()
{
//cout<<"CObject destructor!"<<endl;
}
public:
virtual CRuntimeClass*GetRuntimeClass();
static CRuntimeClass ClassCObject;
public:
bool IsKindOf(CRuntimeClass*pClass)
{
CRuntimeClass *pThis=GetRuntimeClass();
for(;pThis;pThis=pThis->m_pBaseClasss)
{
if(pThis==pClass)
{
return true;
}
}
return false;
}
};
class CRuntimeClass CObject:: ClassCObject=
{
"CObject",sizeof(CObject),0xFFFF,NULL,NULL,NULL
};
static AFX_CLASSINIT _init_CObject(&CObject:: ClassCObject);
CRuntimeClass *CObject::GetRuntimeClass()
{
return &CObject::ClassCObject;
}
CRuntimeClass*CRuntimeClass::pFirstClass=NULL;
/************************************************************************/
/* */
/************************************************************************/
class CCmdTarget:public CObject
{
DECLARE_DYNCREATE(CCmdTarget)
public:
CCmdTarget()
{
//cout<<"CCmdTarget constructor!"<<endl;
//CreateObject();
}
~CCmdTarget()
{
//cout<<"CCmdTarget destructor!"<<endl;
}
};
IMPLEMENT_DYNCREATE(CCmdTarget,CObject)
;
class CWnd:public CCmdTarget
{
DECLARE_DYNCREATE(CWnd)
public:
CWnd()
{
//cout<<"CWnd constructor"<<endl;
}
~CWnd()
{
//cout<<"CWnd destructor"<<endl;
}
public:
virtual bool Create()
{
cout<<"CWnd::Create"<<endl;
CreateEx();
return true;
}
bool CreateEx()
{
cout<<"CWnd::CreateEx"<<endl;
PreCreateWindow();
return true;
}
virtual bool PreCreateWindow()
{
cout<<"CWnd::PreCreateWindow"<<endl;
return true;
}
};
IMPLEMENT_DYNCREATE(CWnd,CCmdTarget)
class CView :public CWnd
{
DECLARE_DYNCREATE(CView)
public:
CView()
{
//cout<<"CView constructor"<<endl;
}
~CView()
{
//cout<<"CView destructor"<<endl;
}
};
IMPLEMENT_DYNCREATE(CView,CWnd)
class CFrameWnd:public CWnd
{
DECLARE_DYNCREATE(CFrameWnd)
public:
CFrameWnd()
{
//cout<<"CFrameWnd constructor"<<endl;
}
~CFrameWnd()
{
//cout<<"CFrameWnd destructor"<<endl;
}
public:
virtual bool Create()
{
cout<<"CFrameWnd::Create"<<endl;
CreateEx();
return true;
}
virtual bool PreCreateWindow()
{
cout<<"CFrameWnd::PreCreateWindow"<<endl;
return true;
}
};
IMPLEMENT_DYNCREATE(CFrameWnd,CWnd)
class CWinThread:public CCmdTarget
{
public:
CWinThread()
{
//cout<<"CWinThread constructor"<<endl;
}
~CWinThread()
{
//cout<<"CWinThread destructor"<<endl;
}
public:
virtual bool InitInstance()
{
cout<<"CWinThread::InitInstance"<<endl;
return true;
}
virtual bool Run()
{
cout<<"CWinThread::Run"<<endl;
return true;
}
};
class CWinApp:public CWinThread
{
public:
CWinApp()
{
//cout<<"CWinApp Constructor "<<endl;
m_currentApp=this;
}
~CWinApp()
{
//cout<<"CWinApp destructor "<<endl;
}
virtual bool InitApplication()
{
cout<<"CWinApp::InitApplication"<<endl;
return true;
}
virtual bool InitInstance()
{
cout<<"CWinApp:InitInstance"<<endl;
return true;
}
virtual bool Run()
{
cout<<"CWinApp::Run"<<endl;
return CWinThread::Run();
}
public:
CWinApp*m_currentApp;
CFrameWnd*m_currentFrameWnd;
};
class CDocument:public CCmdTarget
{
public:
CDocument()
{
//cout<<"CDocument constructor "<<endl;
}
~CDocument()
{
//cout<<"CDocunment destructor "<<endl;
}
};
class CMyFrameWnd:public CFrameWnd
{
DECLARE_DYNCREATE(CMyFrameWnd)
public:
CMyFrameWnd()
{
//cout<<"CMyFrameWnd constructor "<<endl;
Create();
}
~CMyFrameWnd()
{
//cout<<"CMyFrameWnd destructor "<<endl;
}
};
IMPLEMENT_DYNCREATE(CMyFrameWnd,CFrameWnd)
class CMyWinApp:public CWinApp
{
public:
CMyWinApp()
{
//cout<<"CMyWinApp constructor "<<endl;
}
~CMyWinApp()
{
//cout<<"CMyWinApp destructor "<<endl;
}
public:
bool InitInstance()
{
cout<<"CMyWinApp::InitInstance"<<endl;
m_currentFrameWnd=new CMyFrameWnd;
return true;
}
};
CMyWinApp myApp;
CWinApp*AfxGetApp()
{
return myApp.m_currentApp;
}
int main(int argc,char**argv)
{
CWinApp *pApp=AfxGetApp();
pApp->InitApplication();
pApp->InitInstance();
pApp->Run();
CRuntimeClass *pClass;
CObject *pOb;
cout<<"以下为类型型录链表中的所有类的名称:"<<endl;
for(pClass=CRuntimeClass::pFirstClass;pClass;pClass=pClass->m_pBaseClasss)
{
cout<<pClass->m_lpszClassName<<endl;
}
while(1)
{
pClass=CRuntimeClass::Load();
if(!pClass)
{
cout<<"找不到此类!!!"<<endl;
}
else
{
pOb=pClass->CreateObject();
if(pOb)
{
cout<<"创建成功!"<<endl;
}
}
}
return 0;
}</span>
相关文章推荐
- 深入浅出MFC学习笔记:(第三章MFC六大关键技术之仿真:类型识别,动态创建)
- 深入浅出MFC学习笔记:(第三章MFC六大关键技术之仿真:类型识别,动态创建) .
- 深入浅出MFC学习笔记:MFC六大关键技术仿真之RTTI运行时类型识别
- 深入浅出MFC学习笔记:MFC六大关键技术仿真之动态生成
- 深入浅出MFC学习笔记(第三章:MFC六大关键技术之仿真:消息映射)
- 深入浅出mfc学习笔记——六大关键技术之仿真_运行时和动态创建
- 深入浅出MFC学习笔记:MFC六大关键技术仿真之RTTI运行时类型识别
- 深入浅出MFC学习笔记(第三章:MFC六大关键技术之仿真:消息映射)
- 深入浅出MFC学习笔记:MFC六大关键技术仿真之动态生成
- MFC执行期类型识别与动态创建技术内幕
- MFC六大关键技术剖析之动态创建
- MFC六大关键技术之运行时类型识别
- MFC六大关键技术之(二)——运行时类型识别(RTTI)
- MFC技术内幕系列之(三)----MFC执行期类型识别与动态创建技术内幕
- MFC复习(四)MFC执行期类型识别与动态创建技术
- MFC六大关键技术之(三)——动态创建
- MFC六大关键技术之运行时类型识别
- MFC六大关键技术之(三)——动态创建
- MFC六大关键技术之(二)——运行时类型识别(RTTI)
- MFC执行期类型识别与动态创建技术内幕