软件英才网软件行业驰名招聘网站有需要请联系我们第三章:MFC六大关键技术之仿真:类型识别深入理解MFC的内部运行原理,是本次学习《深入浅出MFC》的主要目的。要模仿的六大技术包括:1:MFC程序的初始化过程。2:RTTI(Runtimetypeidentification)运行时类型识别。3:Dynamiccreation动态创建4:Persistence永久保存5:消息映射6:消息传递。RTTI(运行时类型识别)IsKindOf能够侦测某个对象是否属于某种类。即判断某一对象所属的类是否是父类或当前类;要达到动态类型识别的能力,必须在构建类继承体系时记录必要的信息,这被称为类型型录表。MFC以链表的方式建立了此表。类型型录表的每个元素为CRuntimeClass类型,其定义为:[cpp]viewplaincopyclassCRuntimeClass{public:LPCSTRm_lpszClassName;//对象所属类名Intm_nObjectSize;//对象大小软件英才网软件行业驰名招聘网站有需要请联系我们UINTm_wSchema;//模式号CObject*(PASCAL*m_pfnCreateObject)();//构建函数抽象类为NULLCRuntimeClass*pBaseClasss;//基类CRuntimeClass对象指针。StaticCRuntimeClass*pFirstClass;//链表头指针。CRuntimeClass*m_pNextClass;//下一指针。};MFC使用此类作为每个类的成员变量。使用宏定义为每个类定义了自己的CRuntimeClass成员变量。DECLAR_DYNAMIC和IMPLENMENT_DYNAMIC宏使用这两个宏将CRuntimeClass对象不知不觉放到类之中。DECLARE_DYNMIC宏定义如下:[cpp]viewplaincopy#defineDELCARE_DYNMIC(class_name)\public:\staticCRuntimeClassclass##class_name\virtualCRuntimeClass*GetRuntimeClass()const;##用来告诉编译器把两个字符串连接起来。如果使用这个宏:DELCARE_DYNMIC(CView);那么预编译器将生成下列代码:[cpp]viewplaincopy软件英才网软件行业驰名招聘网站有需要请联系我们public:staticCRuntimeClassclassCView;virtualCRuntimeClass*GetRuntimeClass()const;以上代码仅仅是在类中定义CRuntimeClass对象,并定义一个返回CRuntimeClass对象地址的函数。注意CRuntimeClass是static的,也就是说同一种类继承体系的对象共享一个CRuntimeClass对象。初始化对象的内容以及建立类型型录表需要使用IMPLEMENT_DYNMIC宏。[cpp]viewplaincopy#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是一个类,看着跟宏定义似的,这样做很容易让人迷惑。它用于将本节点连接到类型型录表,定义如下:[cpp]viewplaincopyclassAFX_CLASSINIT{public:AFX_CLASSINIT(CRuntimeClass*pNewClass)//构造函数{pNewClass-m_pNextClass=CRuntime::pFirstClass;CRuntimeClass::pFirstClass=pNewClass;}};软件英才网软件行业驰名招聘网站有需要请联系我们用法:[cpp]viewplaincopyclassCWnd:publicCCmdTarget{public:DECLARE_DYNAMIC(CWnd);};IMPLEMENT_DYNMIC(CWnd,CCmdTarget);代码展开后为;[cpp]viewplaincopyclassCWnd: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内使用定义好的宏。[cpp]viewplaincopyclassCObject{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对象与类类型型录中的元素进行比较。如:[cpp]viewplaincopyclassCObject{软件英才网软件行业驰名招聘网站有需要请联系我们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。如:[cpp]viewplaincopy#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为例,下列程序代码:[cpp]viewplaincopyclassCFrameWnd:publicCWnd软件英才