深入浅出MFC学习笔记(第三章MFC六大关键技术之仿真类型识别,动态创建)

合集下载

第3章 Visual C++ 6.0中的MFC

第3章  Visual C++ 6.0中的MFC

3.4.4 CDocument
CDocument类为应用程序的文档对象为自定义文档类提 类为应用程序的文档对象为自定义文档类提 供了基本功能。一个文档代表了一个数据单位。 供了基本功能。一个文档代表了一个数据单位。CDocument 类代表了支持标准的操作,像创建文档、加载文档、 类代表了支持标准的操作,像创建文档、加载文档、存储文 档。
3.5
MFC的消息和命令 MFC的消息和命令
Windows应用程序是基于消息驱动的。鼠标的单击、移 应用程序是基于消息驱动的。鼠标的单击、 应用程序是基于消息驱动的 双击,键盘的按键动作,窗口移动、打开、显示、 动、双击,键盘的按键动作,窗口移动、打开、显示、关闭 等等, 等等,都会有相应的消息及相应的消息处理函数来处理这些 动作。本节讲述消息的知识。 动作。本节讲述消息的知识。
3.5.3 消息映射机制
下面通过举例来说明MFC的消息映射机制。 的消息映射机制。 下面通过举例来说明 的消息映射机制
3.5.4 用户自定义消息
Visual C++ 6.0为程序开发人员预留了常量 为程序开发人员预留了常量WM_USER, 为程序开发人员预留了常量 , 帮助程序开发人员实现自定义消息。 帮助程序开发人员实现自定义消息。下面介绍如何使用自定 义消息。 义消息。
3.1
什么是MFC 什么是MFC
MFC是微软基本类库的缩写形式。MFC提供面向对象框 是微软基本类库的缩写形式。 是微软基本类库的缩写形式 提供面向对象框 程序开发人员可以使用MFC创建 创建Windows应用程序。 应用程序。 架,程序开发人员可以使用 创建 应用程序 MFC是按照 是按照C++类的层次形式组织在一起。高层类提供一般 类的层次形式组织在一起。 是按照 类的层次形式组织在一起 功能,低层类实现更具体的行为, 功能,低层类实现更具体的行为,低层类是从高层类中派生 而来的,因而继承了高层类的行为。 而来的,因而继承了高层类的行为。 MFC可以处理很多 可以处理很多Windows相关的常见任务。例如,程 相关的常见任务。 可以处理很多 相关的常见任务 例如, 序员不必重复开发消息处理循环, 可以实现这一循环, 序员不必重复开发消息处理循环,MFC可以实现这一循环, 可以实现这一循环 并提供简单易用的成员函数, 并提供简单易用的成员函数,如OnPaint()。 。 MFC还提供了一个文档 视图的应用程序开发模型。这是 还提供了一个文档/视图的应用程序开发模型 还提供了一个文档 视图的应用程序开发模型。 将应用程序数据和用户界面元素分离的一种应用编程方法。 将应用程序数据和用户界面元素分离的一种应用编程方法。 文档/视图模型的优势非常强大 视图模型的优势非常强大, 文档 视图模型的优势非常强大,绝大多数应用程序都可以使 用这一模型。 用这一模型。

深入浅出MFC学习笔记

深入浅出MFC学习笔记
};
AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass *pNewClass) {
pNewClass->m_pNextClass = CRuntimeClass::pFirstClass; CRuntimeClass::pFirstClass = pNewClass; }
在 MFC 中保存了一棵类的家族树,CObject 是根结点,其他的类都是他的后代(有几个特 殊的除外,如: CPoint 等)。由于类的家族树存放的是类的信息——不是对象的信息,因此 只需要保存一个就够了,所以 MFC 将这棵树保存为 static 类型。
MFC 类的家族树和数据结构中的树并不相同,普通的树通过跟结点就可以访问所有的结点 (包括叶子)。但在 MFC 中却不行——它只能逆向地从叶子结点向根结点方向访问(从父 结点访问不到子结点)。
size_t n, size_t size, int (*cmp)(const void *keyval, const void *datum)); 想一想开发 bsearch 函数的人怎么会知道两个元素的是什么,怎么比较大小呢?因此就必须 留给用户要自己定义 cmp 函数了! 回调函数一般都有固定的格式(不知道是否会用变参数的情况),不然可能会发生错误。回
void main() {
A *pa = new B; pa->display(); }
执行的结果却打印是:class B
让人感觉不解的地方就是 pa 明明是类 A 的指针,却是执行了类 B 的函数(不可原谅)!!! 其实有这种感觉的人在不知不觉中就犯了一个形而上的错误:用 C 语言的函数行为来套用 display()的行为。在此我想提醒一点:把 C++当作一个新的语言,C 只是参考,不是金科玉 律,切记!!!

MFC学习笔记

MFC学习笔记

MFC程序也有一个WinMain函数,这个函数是我们在编译链接的时候由链接器将WinMain函数链接进来的。

这个函数在APPMODUL.CPP中。

带有Afx的属于应用程序框架类的函数,应用程序框架是辅助我们生成应用程序的框架模型,这个框架模型把很多类或者类与类之间做了一个有机的集成提供给我们,我们可以根据框架模型提供的类库来设计我们自己的应用程序,Af即Application frame 看看这些类如何和我们WinMain函数关联到一起的?CmainFrame的名字是不会变的,其它的都是C+工程名+App/Doc/View命名。

class CTestApp : public CwinApp,可以看到CtestApp是从CwinApp派生出来的。

当我们双击CtestApp这个类时,我们可以看到VC++6.0上面显示我们进入了Test.h头文件中,当把CtestApp展开时,然后双击任何一个函数名,包括构造函数名,析构函数名…我们可以看到VC++6.0上面显示我们进入了Test.cpp源文件中。

且这种情况和我们直接从Fileview 资源卡中直接进入相应的头文件和源文件是一样的效果。

其它类也是相似的操作进入头文件和源文件。

不管是全局变量还是在全局对象CTestApp theApp;,它们都是在程序运行之前,也就是在入口函数WinMain函数加载之前,就已经为它们分配好了内存空间,作为全局函数,就要调用构造函数创建内存空间。

所以是先运行全局对象CTestApp theApp,调用它的构造函数,然后才运行WinMain。

为什么要定义一个全局对象呢?为什么要让它在WinMain之前完成呢?全局对象theApp又有什么作用?CtestApp是从CwinApp派生出来的,theApp是应用程序对象,是一个全局对象,每一个MFC程序当中有且仅有一个从CwinApp派生出来的类,也只能有一个应用程序类实例化的对象,它就表示了我们应用程序本身。

MFC四大关键技术

MFC四大关键技术

MFC六大关键技术(第四部分)——永久保存(串行化)先用一句话来说明永久保存的重要:弄懂它以后,你就越来越像个程序员了!如果我们的程序不需要永久保存,那几乎可以肯定是一个小玩儿。

那怕我们的记事本、画图等小程序,也需要保存才有真正的意义。

对于MFC的很多地方我不甚满意,总觉得它喜欢拿一组低能而神秘的宏来故弄玄虚,但对于它的连续存储(serialize)机制,却是我十分钟爱的地方。

在此,可让大家感受到面向对象的幸福。

MFC的连续存储(serialize)机制俗称串行化。

“在你的程序中尽管有着各种各样的数据,serialize机制会象流水一样按顺序存储到单一的文件中,而又能按顺序地取出,变成各种不同的对象数据。

”不知我在说上面这一句话的时候,大家有什么反应,可能很多朋友直觉是一件很简单的事情,只是说了一个“爽”字就没有下文了。

要实现象流水一样存储其实是一个很大的难题。

试想,在我们的程序里有各式各样的对象数据。

如画图程序中,里面设计了点类,矩形类,圆形类等等,它们的绘图方式及对数据的处理各不相同,用它们实现了成百上千的对象之后,如何存储起来?不想由可,一想头都大了:我们要在程序中设计函数store(),在我们单击“文件/保存”时能把各对象往里存储。

那么这个store()函数要神通广大,它能清楚地知道我们设计的是什么样的类,产生什么样的对象。

大家可能并不觉得这是一件很困难的事情,程序有能力知道我们的类的样子,对象也不过是一块初始化了存储区域罢了。

就把一大堆对象“转换”成磁盘文件就行了。

即使上面的存储能成立,但当我们单击“文件/打开”时,程序当然不能预测用户想打开哪个文件,并且当打开文件的时候,要根据你那一大堆垃圾数据new出数百个对象,还原为你原来存储时的样子,你又该怎么做呢?试想,要是我们有一个能容纳各种不同对象的容器,这样,用户用我们的应用程序打开一个磁盘文件时,就可以把文件的内容读进我们程序的容器中。

第3章 MFC编程基础知识

第3章  MFC编程基础知识

Visual C++ Program Design
MFC的设计原理 3.1.2 MFC的设计原理
MFC向软件开发者提供一组服务 , MFC 向软件开发者提供一组服务, 来协调应 向软件开发者提供一组服务 用程序。在很多情况下,MFC在幕后执行一系列 用程序 复杂的操作,它向程序员提供了更加简单的编程 界面,并可掩盖Windows API的一些缺点(MFC类 的许多成员函数,如MessageBox()中提供了缺省 参数,这减轻了程序员编程的负担)。 MFC 采用面向对象的设计方法 , 将 Windows API中的相关部分组合到 C++类或对象中 中的相关部分组合到C++ 类或对象中。 API 中的相关部分组合到 C++ 类或对象中 。 例如 CWnd类封装了大部分有关窗口处理的API 函数。 作为编程人员,不必记忆大量API 函数,需要作 的只是实例化CWnd类的一个实例,并调用相应的 成员函数即可。
Visual C++ Program Design
概述(续)
对于初学者,只需要清楚自己的代码往什么地方添加就可以 (5) 缺乏面向对象分析能力。面向对象的分析要求搞清楚一 个系统中有哪些类、各个类之间有哪些联系,尤其是在编写基于 文档/视图结构的应用程序时。该方面能力的培养要靠多分析一 些程序中类之间的关系,并要参考相关方面的书籍介绍。 本章把MFC类库中的主要类以层次结构做了一个简单的介绍, 并对MFC应用程序的架构做了描述。对于MFC应用程序的学习,刚 开始要“不求甚解”,懂得代码的放置以及原理就可以了,随着 学习的深入,在查看MFC源代码后,就能逐渐了解到该类型应用 程序的执行流程,从而最终掌握MFC应用程序的开发。

MFC六大关键技术

MFC六大关键技术

MFC六大关键技术是什么?1MFC程序的初始化过程2RTTI 动态类型标识3Dynamic Creation 动态生成4Persistence 永久保留5Message Mapping 信息映射6Message Routing 信息传递怎样自制RTTI?我们作为类库的设计者要在类构造起来的时候,记录必要的信息,以建立型录。

型录中的类的信息,最好以链表方式连接起来。

一般“类别型录”是一个结构,其中至少需要类名字,链表的Next 指针,以及链表的First指针。

First属于整体变量,一份就好,所以用static修饰。

为了将每一个类都能拥有成员变量集合,并且最好有一定的命名规则,然后经某种手段将整个类库构造好之后,“类别型录”(就是各个CRuntimeClass对象)则能呈现为:什么是DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC 宏?作用就是完成RTTI的“类别型录”。

为了将一个类对象塞到类之中,并定义一个可以捕捉到该对象地址的函数,定义一个宏为:#define DECLARE_DYNAMIC(class_name)public:static CRuntimeClass class##class_name;virtual CRuntimeClass* GetRuntimeClass()const;比如我使用了DECLARE_DYNAMIC(CView)编译器预处理器为我做出的代码是:public:static CRuntimeClass classCView;virtual CRuntimeClass * GetRuntimeClass()const;也就是定义类时,将类放入DECLARE_DYNAMIC宏就是把要放的对象放到了里边。

具体连接工作是由IMPLEMENT_DYNAMIC宏来实现:#define IMPLEMENT_DYNAMIC(class_name,base_class_name)_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NULL)这里不做扩展,总之,IMPLEMENT_DYNAMIC内容不仅制定初值,它使用了一个struct AFX_CLASSINIT {AFX_CLASSINTI(CRuntimeClass * pNewClass);};(c++的struct和class都有构造函数):AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass*pNewClass){ pNewClass->m_NextClass = CRuntimeClass::pFirstClass; CRuntimeClass::pFirstClass = pNewClass;}就是上边的这个构造函数完成了连接工作。

MFC的六大机制

MFC的六大机制

MFC的六⼤机制MFC的六⼤机制程序的初始化过程运⾏时类型识别动态创建永久保存消息映射命令传递运⾏时类型识别MFC的运⾏时类型识别就是在程序运⾏过程中判断某个对象是否属于某个类,MFC通过为需要进⾏运⾏时类型识别的类添加⼀个静态CRuntimeClass类对象,其属于此类⽽不是属于某⼀特定对象,其在没有实例化对象的时候就已经存在并且可以被使⽤。

struct CRuntimeClass{//省略其他⽆关的成员LPCSTR m_lpszClassName; //类的名称int m_nObjectSize; //类的⼤⼩CRuntimeClass* m_pBaseClass; //指向基类的CRuntimeClass对象CRuntimeClass* m_pNextClass; //指向同类型对象的CRuntimeClass对象};然后提供了⼀个能返回类⾃⾝CRuntimeClass对象地址的函数GetRuntimeClass()CRuntimeClass* class_name::GetRuntimeClass() const/{ return &class_name::class##class_name;}CObject类提供⼀个IsKindof虚拟函数,此函数通过从对象⾃⼰的CRuntimeClass成员对象开始往基类遍历,判断是否有CRuntimeClass成员对象等于待判断类的CRuntimeClass成员对象,有则说明此对象属于此类(也就是说此对象是此类或其派⽣类的实例),⽆则说明不属于此类。

BOOL CObject::IsKindof(const CRuntimeClass *pClass) const{CRuntimeClass* pClassThis=GetRuntimeClass();while(pClassThis != NULL){if(pClassThis==pClass)return TRUE;pClassThis=pClassThis->m_pBaseClass;}return FALSE;}例如:IsKindof()最后就会返回TRUE,因为MFC⾃⼰定义的类都实现了运⾏时类型识别,⽽所有的类都是从CObject中派⽣的,所以CWnd类的对象实例属于CObject类。

3.MFC原理介绍

3.MFC原理介绍

3.MFC原理介绍包括C++封装原理和MFC六⼤关键技术,以及类向导和MFC应⽤程序向导的使⽤⽅法。

讲解MFC消息映射机制的原理、消息映射函数的建⽴,以及消息发送和接收的⽅法。

CTime类,C语⾔中time函数void CTmDlg::OnButton1(){CTime t = CTime::GetCurrentTime();int nYear = t.GetYear();int nMonth = t.GetMonth();int nDay = t.GetDay();int nHour = t.GetHour();int nMin = t.GetMinute();int nSec = t.GetSecond();int nWeek = t.GetDayOfWeek();//周三CString str;str.Format("当前时间是:%d年%02d⽉%02d⽇ %02d:%02d:%02d",nYear,nMonth,nDay,nHour,nMin,nSec);//AfxMessageBox(str);SetWindowText(str);//SetTimer}void CTmDlg::OnButton2(){time_t tt = time(NULL);tm * pTime = localtime(&tt);int nYear = pTime ->tm_year+1900;int nMonth = pTime ->tm_mon+1;int nDay = pTime ->tm_mday;int nHour = pTime ->tm_hour;int nMin = pTime ->tm_min;int nSec = pTime ->tm_sec;CString str;str.Format("当前时间是:%d年%02d⽉%02d⽇ %02d:%02d:%02d",nYear,nMonth,nDay,nHour,nMin,nSec);//AfxMessageBox(str);SetWindowText(str);//SetTimer}类// MyTime.h: interface for the CMyTime class.////////////////////////////////////////////////////////////////////////#if !defined(AFX_MYTIME_H__A7F50C7B_E6B7_4ED5_BB03_E00EB9935406__INCLUDED_)#define AFX_MYTIME_H__A7F50C7B_E6B7_4ED5_BB03_E00EB9935406__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000//⾯向对象(C++)特点:抽象,封装和派⽣,(多态)#include <time.h>class CMyTime{time_t m_time;public:int GetYear() const;static CMyTime GetCurrentTime();CMyTime();~CMyTime();};#endif // !defined(AFX_MYTIME_H__A7F50C7B_E6B7_4ED5_BB03_E00EB9935406__INCLUDED_)// MyTime.h: interface for the CMyTime class.////////////////////////////////////////////////////////////////////////#if !defined(AFX_MYTIME_H__A7F50C7B_E6B7_4ED5_BB03_E00EB9935406__INCLUDED_)#define AFX_MYTIME_H__A7F50C7B_E6B7_4ED5_BB03_E00EB9935406__INCLUDED_#if _MSC_VER > 1000#pragma once#endif// _MSC_VER > 1000//⾯向对象(C++)特点:抽象,封装和派⽣,(多态)#include <time.h>class CMyTime{time_t m_time;public:int GetYear() const;static CMyTime GetCurrentTime();CMyTime();~CMyTime();};#endif// !defined(AFX_MYTIME_H__A7F50C7B_E6B7_4ED5_BB03_E00EB9935406__INCLUDED_)#include "stdafx.h"#include <time.h>#include <stdio.h>#include "MyTime.h"int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){CMyTime t = CMyTime::GetCurrentTime();int nYear = t.GetYear();//CTime time;/* time_t tt = time(NULL);tm * pTime = localtime(&tt);int nYear = pTime ->tm_year+1900;int nMonth = pTime ->tm_mon+1;int nDay = pTime ->tm_mday;int nHour = pTime ->tm_hour;int nMin = pTime ->tm_min;int nSec = pTime ->tm_sec;char s[200];sprintf(s,"当前时间是:%d年%02d⽉%02d⽇ %02d:%02d:%02d",nYear,nMonth,nDay,nHour,nMin,nSec);MessageBox(NULL,s,"提⽰",0);*/return0;}MFC所有封装类⼀共200多个,但是MFC的内部技术不只是简单的封装。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第三章:MFC六大关键技术之仿真:类型识别深入理解MFC的内部运行原理,是本次学习《深入浅出MFC》的主要目的。

要模仿的六大技术包括:1:MFC程序的初始化过程。

2:RTTI(Runtime type identification)运行时类型识别。

3:Dynamic creation 动态创建4:Persistence永久保存5:消息映射6:消息传递。

RTTI(运行时类型识别)IsKindOf能够侦测某个对象是否属于某种类。

即判断某一对象所属的类是否是父类或当前类;要达到动态类型识别的能力,必须在构建类继承体系时记录必要的信息,这被称为类型型录表。

MFC以链表的方式建立了此表。

类型型录表的每个元素为CRuntimeClass类型,其定义为:1class CRuntimeClass23{45public:67LPCSTR m_lpszClassName;//对象所属类名89 Int m_nObjectSize;//对象大小1011UINT m_wSchema;//模式号1213 CObject *(PASCAL*m_pfnCreateObject)();//构建函数抽象类为NULL1415 CRuntimeClass *pBaseClasss;//基类CRuntimeClass对象指针。

1617 Static CRuntimeClass *pFirstClass;//链表头指针。

1819 CRuntimeClass *m_pNextClass;//下一指针。

2021};MFC使用此类作为每个类的成员变量。

使用宏定义为每个类定义了自己的CRuntimeClass成员变量。

DECLAR_DYNAMIC和IMPLENMENT_DYNAMIC宏使用这两个宏将CRuntimeClass对象不知不觉放到类之中。

DECLARE_DYNMIC宏定义如下:22#define DELCARE_DYNMIC ( class_name ) \2324public:\2526static CRuntimeClass class##class_name \2728virtual CRuntimeClass *GetRuntimeClass()const;##用来告诉编译器把两个字符串连接起来。

如果使用这个宏:DELCARE_DYNMIC(CView);那么预编译器将生成下列代码:29public:3031static CRuntimeClass classCView;3233virtual CRuntimeClass*GetRuntimeClass()const;以上代码仅仅是在类中定义CRuntimeClass对象,并定义一个返回CRuntimeClass对象地址的函数。

注意CRuntimeClass是static的,也就是说同一种类继承体系的对象共享一个CRuntimeClass对象。

初始化对象的内容以及建立类型型录表需要使用IMPLEMENT_DYNMIC宏。

34#define IMPLEMENT_DYNMIC (class_name,base_class_name)\3536_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NULL);3738_IMPLEMENT_RUNTIMECLASS又是一个宏,它定义如下:3940#define _IMPLEMENT_RUNTIMECLASS(class_name,\4142 base_class_name,wSchema,pfnNew)\4344static char _lpsz##class_name[]=#class_name;\4546 CRuntimeClass class_name::class##class_name=\4748 { _lpsz##class_name,sizeof(class_name),\4950 wSchema,pfnNew,\5152 RUNTIME_CLASS(base_class_name),NULL\5354 };5556static AFX_CLASSINIT _init##class_name \5758 ( & class_name::class##class_name);\5960 CRuntimeClass *class_name::GetRuntimeClass()const\6162 {\6364return &class_name::class##classname;\6566 }6768#define RUNTIME_CLASS(class_name)\6970 ( &class_name::class##class_name);AFX_CLASSINIT是一个类,看着跟宏定义似的,这样做很容易让人迷惑。

它用于将本节点连接到类型型录表,定义如下:71class AFX_CLASSINIT7273{7475public:7677 AFX_CLASSINIT(CRuntimeClass*pNewClass)//构造函数7879 {8081 pNewClass->m_pNextClass=CRuntime::pFirstClass;8283 CRuntimeClass::pFirstClass =pNewClass;8485 }8687};用法:88class CWnd:public CCmdTarget90{9192public:9394 DECLARE_DYNAMIC(CWnd);959697};IMPLEMENT_DYNMIC(CWnd,CCmdTarget);代码展开后为;98class CWnd:public CCmdTarget99100{101102public:103104static CRuntimeClass classCView;105106virtual CRuntimeClass*GetRuntimeClass()const107108109110};111112113114static char _lpszCWnd[]="CWnd";115116CRuntimeClass CWnd::classCWnd=117118{119120_lpszCView , sizeof(CWnd) , FFFF,NULL , &Wnd::classCWnd , NULL); 121122};123124static AFX_CLASSINIT _init_CWnd(&CWnd::classCWnd);126{127128 Return &CWnd::classCWnd;129130}定义宏的过程很复杂,但是一旦定义好之后,在使用时仅仅两句话就可以完成定义CRuntimeClass对象并且连接类型型录链表的工作。

CObject是所有类的基类,也是链表的头,此类应特别定义,不能在CObject内使用定义好的宏。

131class CObject132133{134135public:136137virtual CRuntimeClass*GetRuntimeClass()const;138139static CRuntimeClass classCObject;140141};142143static char szCobject[]="CObject";144145struct CRuntimeClass CObject::classCObject=146147{148149 szCObject ,sizeof(CObject),0xFFFF,NULL,NULL,NULL150151};152153static AFX_CLASSINIT _init_CObject(&Cobject::classObject);154155CRuntimeClass *CObject::GetRuntimeClass()const156157{158159return &CObject::classCObject;160161}由于CRuntimeClass对象是static成员变量,因此需要在类外初始化。

如果忘记初始化将会报链接错误。

CRuntimeClass*CRuntimeClass::pFirstClass=NULL;建好了类类型路表,要实现IsKindOf功能很容易。

首先在CObject加上一个IsKindOf函数,于是所有继承自此类的类都具有类型识别的功能。

能够将某个CRuntimeClass对象与类类型型录中的元素进行比较。

如:162class CObject163164{165166public:167168bool IsKindOf(const CRuntimeClass*pClass)const169170{171172 CRuntimeClass *pClassThis=GetRuntimeClass();173174while(pClassThis)175176 {177178if(pClassThis==pClass)179180return true;181182 pClassThis=pClassThis->m_pBaseClass;//沿着基类寻找。

183184 }185186return false;187188}189190};如果我们调用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。

如:191#define DECLARE_DYNCREATE(class_name)\192193 DECLARE_DYNCREATE(class_name)\194195static CObject *PASCAL CreateObject();196197#define IMPLEMENT_DYNCREATE (class_name,base_class_name)\ 198199 CObject*PASCAL class_name::CreateObject()\200201 {return new classname;};\202203 _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name, 204205 0xFFFF,class_name::CreateObject)以CFrameWnd为例,下列程序代码:206class CFrameWnd:public CWnd207208{209210public:211212 DECLEARE_DYNCREATE(CFrameWnd);213214};IMPLEMENT_DYNCREATE(CFrameWnd,CWnd);展开如下:215class CFrame:public CWnd216217{218219public:220221static CRuntimeClass classCFrameWnd;222223virtual CRuntimeClass *GetRuntimeClass()const;224225static CObject *PASCAL CreateObject();226227};228229CObject _PASCAL CFrameWnd::CreateObject()230231{232233return new CFrameWnd;234}235236static char _lpszCFrameWnd[]="CFrameWnd";237238CRuntimeClass CFrameClass::classCFrameWnd={239240_lpszCFrameWnd,sizeof(CFrameWnd),0xFFFF,CFrameWnd::CreateObject,RUNTIME_CALSS(CW nd),NULL};241242static AFX_CLASSINIT _init_CFrameWnd243244 (&CFrameWnd::classCFrameWnd);245246CRuntimeClass*CFrameWnd::GetRunimeClass()const247248{return &CFrameWnd::classCFrameWnd;}注意对象构建函数为static函数。

相关文档
最新文档