第三章:MFC六大关键技术之仿真:类型识别
深入理解MFC的内部运行原理,是本次学习《深入浅出MFC》的主要目的。要模仿的六大技术包括:
1:MFC程序的初始化过程。
2:RTTI(Runtimetypeidentification)运行时类型识别。
3:Dynamiccreation动态创建
4:Persistence永久保存
5:消息映射
6:消息传递。
RTTI(运行时类型识别)
IsKindOf能够侦测某个对象是否属于某种类。即判断某一对象所属的类是否是父类或当前类;
要达到动态类型识别的能力,必须在构建类继承体系时记录必要的信息,这被称为类型型录表。MFC以链表的方式建立了此表。
类型型录表的每个元素为CRuntimeClass类型,其定义为:
classCRuntimeClass
{
public:
LPCSTRm_lpszClassName;//对象所属类名
Intm_nObjectSize;//对象大小
UINTm_wSchema;//模式号
CObject*(PASCAL*m_pfnCreateObject)();//构建函数抽象类为NULL
CRuntimeClass*pBaseClasss;//基类CRuntimeClass对象指针。
StaticCRuntimeClass*pFirstClass;//链表头指针。
CRuntimeClass*m_pNextClass;//下一指针。
};
MFC使用此类作为每个类的成员变量。使用宏定义为每个类定义了自己的CRuntimeClass成员变量。
DECLAR_DYNAMIC和IMPLENMENT_DYNAMIC宏
使用这两个宏将CRuntimeClass对象不知不觉放到类之中。
DECLARE_DYNMIC宏定义如下:
#defineDELCARE_DYNMIC(class_name)\
public:\
staticCRuntimeClassclass##class_name\
virtualCRuntimeClass*GetRuntimeClass()const;
##用来告诉编译器把两个字符串连接起来。
如果使用这个宏:DELCARE_DYNMIC(CView);
那么预编译器将生成下列代码:
public:
staticCRuntimeClassclassCView;
virtualCRuntimeClass*GetRuntimeClass()const;
以上代码仅仅是在类中定义CRuntimeClass对象,并定义一个返回CRuntimeClass对象地址的函数。注意CRuntimeClass是static的,也就是说同一种类继承体系的对象共享一个CRuntimeClass对象。
初始化对象的内容以及建立类型型录表需要使用IMPLEMENT_DYNMIC宏。
#defineIMPLEMENT_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)\
staticchar_lpsz##class_name[]=#class_name;\
CRuntimeClassclass_name::class##class_name=\
{_lpsz##class_name,sizeof(class_name),\
wSchema,pfnNew,\
RUNTIME_CLASS(base_class_name),NULL\
};
staticAFX_CLASSINIT_init##class_name\
(&class_name::class##class_name);\
CRuntimeClass*class_name::GetRuntimeClass()const\
{\
return&class_name::class##classname;\
}
#defineRUNTIME_CLASS(class_name)\
(&class_name::class##class_name);
AFX_CLASSINIT是一个类,看着跟宏定义似的,这样做很容易让人迷惑。它用于将本节点连接到类型型录表,定义如下:
classAFX_CLASSINIT
{
public:
AFX_CLASSINIT(CRuntimeClass*pNewClass)//构造函数
{
pNewClass->m_pNextClass=CRuntime::pFirstClass;
CRuntimeClass::pFirstClass=pNewClass;
}
};
用法:
classCWnd:publicCCmdTarget
{
public:
DECLARE_DYNAMIC(CWnd);
};
IMPLEMENT_DYNMIC(CWnd,CCmdTarget);
代码展开后为;
classCWnd:publicCCmdTarget
{
public:
staticCRuntimeClassclassCView;
virtualCRuntimeClass*GetRuntimeClass()const
};
staticchar_lpszCWnd[]="CWnd";
CRuntimeClassCWnd::classCWnd=
{
_lpszCView,sizeof(CWnd),FFFF,NULL,&Wnd::classCWnd,NULL);
};
staticAFX_CLASSINIT_init_CWnd(&CWnd::classCWnd);
{
Return&CWnd::classCWnd;
}
定义宏的过程很复杂,但是一旦定义好之后,在使用时仅仅两句话就可以完成定义CRuntimeClass对象并且连接类型型录链表的工作。
CObject是所有类的基类,也是链表的头,此类应特别定义,不能在CObject内使用定义好的宏。
classCObject
{
public:
virtualCRuntimeClass*GetRuntimeClass()const;
staticCRuntimeClassclassCObject;
};
staticcharszCobject[]="CObject";
structCRuntimeClassCObject::classCObject=
{
szCObject,sizeof(CObject),0xFFFF,NULL,NULL,NULL
};
staticAFX_CLASSINIT_init_CObject(&Cobject::classObject);
CRuntimeClass*CObject::GetRuntimeClass()const
{
return&CObject::classCObject;
}
由于CRuntimeClass对象是static成员变量,因此需要在类外初始化。如果忘记初始化将会报链接错误。
CRuntimeClass*CRuntimeClass::pFirstClass=NULL;
建好了类类型路表,要实现IsKindOf功能很容易。首先在CObject加上一个IsKindOf函数,于是所有继承自此类的类都具有类型识别的功能。能够将某个CRuntimeClass对象与类类型型录中的元素进行比较。如:
classCObject
{
public:
boolIsKindOf(constCRuntimeClass*pClass)const
{
CRuntimeClass*pClassThis=GetRuntimeClass();
while(pClassThis)
{
if(pClassThis==pClass)
returntrue;
pClassThis=pClassThis->m_pBaseClass;//沿着基类寻找。
}
returnfalse;
}
};
如果我们调用CWnd*cw=newCWnd;
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。
如:
#defineDECLARE_DYNCREATE(class_name)\
DECLARE_DYNCREATE(class_name)\
staticCObject*PASCALCreateObject();
#defineIMPLEMENT_DYNCREATE(class_name,base_class_name)\
CObject*PASCALclass_name::CreateObject()\
{returnnewclassname;};\
_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,
0xFFFF,class_name::CreateObject)
以CFrameWnd为例,下列程序代码:
classCFrameWnd:publicCWnd
{
public:
DECLEARE_DYNCREATE(CFrameWnd);
};
IMPLEMENT_DYNCREATE(CFrameWnd,CWnd);
展开如下:
classCFrame:publicCWnd
{
public:
staticCRuntimeClassclassCFrameWnd;
virtualCRuntimeClass*GetRuntimeClass()const;
staticCObject*PASCALCreateObject();
};
CObject_PASCALCFrameWnd::CreateObject()
{
returnnewCFrameWnd;
}
staticchar_lpszCFrameWnd[]="CFrameWnd";
CRuntimeClassCFrameClass::classCFrameWnd={
_lpszCFrameWnd,sizeof(CFrameWnd),0xFFFF,CFrameWnd::CreateObject,RUNTIME_CALSS(CWnd),NULL};
staticAFX_CLASSINIT_init_CFrameWnd
(&CFrameWnd::classCFrameWnd);
CRuntimeClass*CFrameWnd::GetRunimeClass()const
{return&CFrameWnd::classCFrameWnd;}
注意对象构建函数为static函数。
为了支持动态创建需要在CRuntimeClass内添加两个函数:CreateObject和CRuntimeClass::Load成员函数。
CObject*CRuntimeClass::CreateObject()
{
If(m_pfnCreateObject==NULL)//不支持动态创建。
{
throwruntime_error("此类不支持动态创建");
ReturnNULL;
}
CObject*pObject=(*m_pfnCreateObject)();
ReturnpObject;
}
CRuntimeClass*PASCLCRuntimeClass::Load()
{
CharszClassName[64];
CRuntimeClass*pClass
cout<<"输入一个类名:";
cin>>szClassName;
for(pClass=pFirstClass;pClass;pClass=pClass->m_pNextClass)
{
if(strcmp(szClassName,pClass->m_lpszClassName)==0)
returnpClass;
returnNULL;
}
}
以下为类型识别及动态创建的完整代码:
分享到:
相关推荐
深入浅出MFC读书笔记3 在MFC中,Document-View架构是一个非常重要的概念。本文将对Document-View架构中的关键组件进行深入探讨,并对其实现思路进行详细的解析。 首先,让我们来看一下Document的概念。在MFC中,...
总之,《深入浅出MFC》第三章的内容涵盖了MFC的核心概念和技术,是Windows开发人员理解和掌握MFC编程的宝贵资源。通过学习这一章,开发者可以构建功能丰富的Windows应用程序,并对MFC有深入的理解。
深入浅出.MFC.pdf深入浅出.MFC.pdf深入浅出.MFC.pdf
《深入浅出MFC》是一本专为C++程序员深入理解Microsoft Foundation Classes (MFC) 库而编写的经典教程。MFC是微软提供的一套C++类库,用于简化Windows应用程序开发,它将Windows API封装成易于使用的C++类。这本书的...
深入浅出MFC读书笔记2是对MFC框架的进一步学习和理解,主要涵盖了MFC的基础概念、类库结构以及程序构建的关键要素。MFC(Microsoft Foundation Classes)是微软为Windows平台开发的应用程序提供的一种类库,它基于...
文件`深入浅出MFC笔记(配合原书的好笔记).doc`可能是作者阅读侯捷的《深入浅出MFC》后所做的详细笔记,可能包含了对书中关键概念的理解、例子的解析以及个人的实践心得。这种学习方式对于巩固理论知识和提高实际编程...
深入浅出.MFC.pdf深入浅出.MFC.pdf深入浅出.MFC.pdf
《深入浅出MFC》是一本专注于Microsoft Foundation Classes (MFC) 的技术书籍,MFC是微软为Windows应用程序开发提供的一套C++类库。它将Windows API进行了封装,使得开发者能够更方便地构建Windows桌面应用程序。MFC...
MFC入门教程:1天深入浅出MFC
MFC 是 Windows 程序设计的基础,深入浅出 MFC 是学习 Windows 程序设计的不二之选。 《深入浅出MFC》读书心得涵盖了 Windows 程序设计的方方面面,包括程序结构、头文件、makefile、消息循环等知识点,为开发者...
第三章 MFC六大关键技术之仿真 第二篇 欲善工事先利其器 第四章 Visual C++ 集成开发环境 第三篇 浅出MFC程序设计 第五章 总观Application Framework 第六章 MFC程序的生死因果 第七章 简单而完整:MFC骨干程序 第四...
《深入浅出MFC》是一本专注于Microsoft Foundation Classes (MFC) 的技术书籍,MFC 是微软为Windows应用程序开发提供的一套C++类库。它将Windows API进行了封装,使得开发者能够更方便地构建基于Windows操作系统的...
深入浅出.MFC.pdf深入浅出.MFC.pdf深入浅出.MFC.pdf
深入浅出.MFC.pdf深入浅出.MFC.pdf深入浅出.MFC.pdf
《深入浅出MFC简体中文版》是一本专注于Microsoft Foundation Classes (MFC) 的技术专著,旨在帮助读者深入理解和应用这一强大的Windows应用程序开发框架。MFC是微软为C++开发者提供的一种库,它封装了Windows API,...
该压缩包包含了《深入浅出MFC》第二版的配套源代码,可供读者在学习过程中实践和探索。 MFC本身是微软为了简化Windows API编程而设计的,它封装了Windows API,使得开发者可以通过面向对象的方式编写Windows应用...