深入浅出MFC学习笔记:(第三章MFC六大关键技术之仿真:类型识别,动态创建) .
来源:互联网 发布:西安淘宝培训班 编辑:程序博客网 时间:2024/05/16 07:39
第三章:MFC六大关键技术之仿真:类型识别
深入理解MFC的内部运行原理,是本次学习《深入浅出MFC》的主要目的。要模仿的六大技术包括:
1:MFC程序的初始化过程。
2:RTTI(Runtime type identification)运行时类型识别。
3:Dynamic creation 动态创建
4:Persistence永久保存
5:消息映射
6:消息传递。
RTTI(运行时类型识别)
IsKindOf能够侦测某个对象是否属于某种类。即判断某一对象所属的类是否是父类或当前类;
要达到动态类型识别的能力,必须在构建类继承体系时记录必要的信息,这被称为类型型录表。MFC以链表的方式建立了此表。
类型型录表的每个元素为CRuntimeClass类型,其定义为:
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宏定义如下:
#define DELCARE_DYNMIC ( class_name ) \public:\ static CRuntimeClass class##class_name \ virtual CRuntimeClass *GetRuntimeClass()const;
##用来告诉编译器把两个字符串连接起来。
如果使用这个宏:DELCARE_DYNMIC(CView);
那么预编译器将生成下列代码:
public:static CRuntimeClass classCView;virtual CRuntimeClass*GetRuntimeClass()const;
以上代码仅仅是在类中定义CRuntimeClass对象,并定义一个返回CRuntimeClass对象地址的函数。注意CRuntimeClass是static的,也就是说同一种类继承体系的对象共享一个CRuntimeClass对象。
初始化对象的内容以及建立类型型录表需要使用IMPLEMENT_DYNMIC宏。
#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是一个类,看着跟宏定义似的,这样做很容易让人迷惑。它用于将本节点连接到类型型录表,定义如下:
class AFX_CLASSINIT{ public: AFX_CLASSINIT(CRuntimeClass*pNewClass)//构造函数 { pNewClass->m_pNextClass=CRuntime::pFirstClass; CRuntimeClass::pFirstClass =pNewClass; }};
用法:
class CWnd:public CCmdTarget{ public: DECLARE_DYNAMIC(CWnd);};
IMPLEMENT_DYNMIC(CWnd,CCmdTarget);
代码展开后为;
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内使用定义好的宏。
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对象与类类型型录中的元素进行比较。如:
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。
如:
#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为例,下列程序代码:
class CFrameWnd:public CWnd{ public: DECLEARE_DYNCREATE(CFrameWnd);};
IMPLEMENT_DYNCREATE(CFrameWnd,CWnd);
展开如下:
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成员函数。
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; }}
以下为类型识别及动态创建的完整代码:
#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)();//构建函数,抽象类为NULLCRuntimeClass *m_pBaseClasss;//基类CRuntimeClass对象指针。static CRuntimeClass *pFirstClass;//链表头指针。staticCRuntimeClass *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;}
- 深入浅出MFC学习笔记:(第三章MFC六大关键技术之仿真:类型识别,动态创建) .
- 深入浅出MFC学习笔记:(第三章MFC六大关键技术之仿真:类型识别,动态创建)
- 深入浅出MFC学习笔记:(第三章MFC六大关键技术之仿真:类型识别,动态创建) .
- 深入浅出MFC学习笔记(第三章:MFC六大关键技术之仿真:消息映射)
- 深入浅出MFC学习笔记(第三章:MFC六大关键技术之仿真:命令传递) .
- 深入浅出MFC学习笔记(第三章:MFC六大关键技术之仿真:消息映射)
- 深入浅出MFC学习笔记(第三章:MFC六大关键技术之仿真:命令传递) .
- 深入浅出MFC学习笔记:MFC六大关键技术仿真之RTTI运行时类型识别
- 深入浅出MFC学习笔记:MFC六大关键技术仿真之动态生成
- 深入浅出MFC学习笔记:MFC六大关键技术仿真之MFC程序的初始化过程
- 三、MFC 六大关键技术之仿真 (学习笔记)
- MFC六大关键技术之仿真学习笔记(一)
- MFC六大关键技术之仿真学习笔记(二)
- MFC六大关键技术之仿真学习笔记(三)
- MFC六大关键技术之仿真学习笔记(四)
- MFC六大关键技术之仿真学习笔记(六)
- MFC六大关键技术之仿真学习笔记(五)
- MFC六大关键技术之仿真学习笔记(七)
- ASP.NET中使用js JavaScript获取FileUpload 文件大小
- 关于Vfp表单全部控件控制【thisform.setall】!(经典)
- Linux 我的配置
- JAVA Web.xml 加载顺序
- Com入门1
- 深入浅出MFC学习笔记:(第三章MFC六大关键技术之仿真:类型识别,动态创建) .
- [补发-新闻] 20120509,微软5月9日发布7个安全补丁
- Android中的横竖屏、资源、国际化的使用
- 什么是回调函数
- AppCan:如何在Android手机上开发出Android应用
- Eclipse3.7默认字体修改-帮你找回Courser-New字体
- c++ email开发
- android 错误收集 SAX解析 解析正常,但是数据不能拿到
- Sencha Touch2中ajax服务给后台传参时对照问题