您的位置:首页 > 其它

深入浅出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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: