刚学习完MFC,一时心血来潮,分析下MFC的几个关键技术,算是对学习的总结。由于本人还是个初学者,能力有限,语言组织欠妥,肯定有不足之处,欢迎批评斧正。
有以下几个部分内容:
1.RTTI(运行期类型识别)
2.动态创建
3.序列化的实现
4.程序的产生,运行和结束 ,以单文档框架程序为例
5.单文档框架程序/类型之间的关系
6.MFC消息机制的流转
7.实现自己的SPY++
RTTI是动态创建的基础,序列化同时用到动态创建和RTTI,所以RTTI是MFC的基石。三者的关系很紧密。.
1. 动态创建可以简单理解为,通过字符串创建对象。比如你封装了一个类CLine,如何仅
仅通过字符串“CLine”创建来CLine类的对象。
2. 序列化是指从持久存储介质中读出或写入一个对象的过程。
举个例子:在一个CAD系统里,用户画了一些线条呀,矩形等等。如何将当前所有图形保存到文件中,下次打开文件,然后正确读取并显示出来。
让我们尝试分析下,假设有两个类CLine, CRectangle分别负责绘制线条和矩形。
CLine里保存线条的起始坐标点。
Crectangle保存矩形的左上角坐标点,以及右下角坐标点。
用户每画一个线条,则创建一个CLine对象,矩形也是如此。
当用户保存线条到文件时,需要保存哪些内容呢?肯定要有CLine的类型信息,类信息至少有类的名字。如果不保存,读取图形文件时,无法创建一个CLine对象,也就不能再正确显示出来。读出对象时,根据字符串“CLine”创建一个CLine对象,即动态创建。
这里保存和读取对象的过程就是序列化,很显然序列化需要动态创建的支持,但是二者共同基础却是RTTI。
RTTI (Run_Time Type Identification),即运行期类型识别,是MFC动态创建的基础,可以对类型进行管理,对类型之间的关系,对象的类型进行识别和检查。
RuntimeClass的结构体,所有具有RTTI和动态创建能力的类都需要添加一个CRuntimeClass静态成员,然后维护一个CRuntimeClass对象的链表,这样就可以保存这些类的相关信息,并在运行时使用相关信息。
MFC 里CRuntimeClass结构的的重要成员:
LPCSTR m_lpszClassName; //类名字符串
int m_nObjectSize; //对象大小
UINT m_wSchema; //被加载类的版本信息
CObject* (PASCAL* m_pfnCreateObject)(); //指向动态创建对象函数的指针
CRuntimeClass* m_pBaseClass; //指向类的成员函数_GetBaseClass,返回基类CRuntimeClass
实现关键:
1.在主函数前,把每个支持RTTI的类都加一个该类型信息结构体对象赋值,通过静态成员变量实现的。
2.在结构体对象构造过程中,完成类型链表的构建,
3.通过IsKindOf,IsDerverFrom处理,遍历列表找到对应的类型。
本文手工模拟实现了一个运行期类型识别程序,
其中一份是宏定义实现的。手工模拟的CMyRunTimeClass
(为简化,只保存了最基本的类信息,参考附件)
链表完成构建后,对类型的查找,判断就很简单了。
以下是关键函数CMyRunTimeClass::IsDerivedFrom函数的实现:
//判断当前类是否从pBaseClass派生
bool CMyRunTimeClass::IsDerivedFrom(
const CMyRunTimeClass*pBaseClass)
{
CMyRunTimeClass *pCurrent =this;
while (pCurrent != NULL)
{
if (pCurrent ==pBaseClass)
{ return true; }
//向上找父类的类型信息结构体对象
pCurrent = pCurrent->m_pBaseClass;
}
return false;
}