深入浅出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的内部技术不只是简单的封装。

MFC 教程 第3章 MFC基础

MFC 教程 第3章 MFC基础



重写CWinApp派生类的虚函数InitInstance。在 这个函数中,按自己的需要创建和显示窗口。 在CDocument的派生类中,声明程序所需的数 据和对这些数据进行必要操作的接口函数。 在CView类的派生类中编写处理消息的代码。 如果在消息处理中需要文档中的数据,则应该 调用该类的成员函数GetDocument来获取文档 对象,然后通过文档对象的接口函数对文档中 的数据进行操作。 在CView类的派生类中的OnDraw函数中编写窗 口重绘时的代码。 用宏实现类的消息映射表 23
3.4 对象的动态创建

在MFC应用程序中,类的对象一般都是动 态创建的.通过从文件中获得某个类的信 息之后,利用这些信息恢复或创建该类的 对象.因此,需要一个结构,专门存储这个类 的相关信息.
24
类信息表: struct CRuntimeClass { LPCSTR m_lpszClassName; …… CRuntimeClass* m_pBaseClass; CRuntimeClass* m_pNextClass; };
13
3.3.1 文档\视图类的基本概念
在文档\视图结构的框架中, 视图类CView类的对象用来显示数据并接受 用户操作, 框架窗口类CFrameWnd是视图类对象的容器。 文档类对象在幕后存储和管理数据,因此文 档类对象在程序界面上看不到。
14
3.3.2 文档类CDocument
文档类CDocument对象存储和管理应用程 序的数据。
25
与处理消息映射类似,MFC把在类中声明 类信息表的代码封装在宏 DECLARE_DYNCREATE中,而把实现类信 息表和链表的代码封装在了宏 IMPLEMENT_DYNCREATE中.因此,凡是 设计具有动态创建对象能力的类时,都要 使用这两个宏.

MFC六大核心机制

MFC六大核心机制

MFC六⼤核⼼机制MFC六⼤核⼼机制概述我们选择了C++,主要是因为它够艺术、够⾃由,使⽤它我们可以实现各种想法,⽽MFC将多种可灵活使⽤的功能封装起来,我们岂能忍受这种“⿊盒”操作?于是研究分析MFC的核⼼机制成为必然。

⾸先,列出要讲的MFC六⼤核⼼机制:1、MFC程序的初始化。

2、运⾏时类型识别(RTTI)。

3、动态创建。

4、永久保存。

5、消息映射。

6、消息传递。

本⽂讲第⼀部分,MFC程序的初始化过程。

简单的MFC窗⼝程序设计⼀个简单完整MFC程序,产⽣⼀个窗⼝。

当然这不能让AppWizard⾃动为我们⽣成。

我们可以在Win32 Application⼯程下⾯那样写:C++代码1 #include <afxwin.h>2class MyApp : public CWinApp3 {4public:5 BOOL InitInstance() //②程序⼊点6 {7 CFrameWnd *Frame=new CFrameWnd();//构造框架8 m_pMainWnd=Frame; //将m_pMainWnd设定为Frame;9 Frame->Create(NULL,"最简单的窗⼝");//建⽴框架10 Frame->ShowWindow(SW_SHOW); //显⽰框架11return true; //返回12 }13 };14 MyApp theApp; //①建⽴应⽤程序。

View Code设定链接MFC库,运⾏,即可看见⼀个窗⼝。

从上⾯,⼤家可以看到建⽴⼀个MFC窗⼝很容易,只⽤两步:⼀是从CWinApp派⽣⼀个应⽤程序类(这⾥是MyApp),然后建⽴应⽤程序对象(theApp),就可以产⽣⼀个⾃⼰需要的窗⼝(即需要什么样就在InitInstance()⾥创建就⾏了)。

整个程序,就改写⼀个InitInstance()函数,创建那么⼀个对象(theApp),就是⼀个完整的窗⼝程序。

MFC原理第四讲.动态创建机制

MFC原理第四讲.动态创建机制

MFC原理第四讲.动态创建机制 MFC原理第四讲.动态创建机制⼀⼂要学习的知识点以及简介 动态创建是什么意思? 动态创建其实就是跟C++的new⼀样.都是创建对象.但是规避了C++语法的缺陷.例如: char * ClassName = "CMyApp" CObject *obj = new ClassName;C++ 中不允许这样编写代码要学习的知识点 1.DECLARE_DYNCREATE 宏学过上讲RTTI的应该明⽩.这个就是个⽂字替换. 也可以说这个宏是⼀个声明宏当然也有实现宏 2.IMPLEMENT_DYNCREATE还需要了解CRuntimeClass 结构. ⽀持动态创建的成员.struct CRuntimeClass{LPCSTR m_lpszClassName; 类名int m_nObjectSize; 类⼤⼩UINT m_wSchema; 类编号CObject* (PASCAL* m_pfnCreateObject)(); 存放⽀持动态创建的类CRuntimeClass* m_pBaseClass;// OperationsCObject* CreateObject(); 动态创建函数BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const; 判断函数...CRuntimeClass* m_pNextClass; 链表存储执向下⼀个};⼆⼂如何使⽤动态创建. ⽀持动态创建的是跟窗⼝有关的. 也就是CFrameWnd类. 如果我们继承了这个类.我们也可以让他⽀持动态创建. 1.添加声明宏 2.添加实现宏 3.动态创建使⽤.添加声明宏则添加到我们继承CFrameWnd类中即可. 实现宏则在外边参数填写⾃⼰的类名添加实现宏使⽤动态创建. 在InitInstance⾥⾯使⽤即可.我们的new 窗⼝改成动态创建即可.RUNTIME_CLASS宏可以拆解开.m_pMainWnd = (CMainWnd *)((CRuntimeClass*)(&CMainWnd::classCMainWnd))->CreateObject();应⽤程序实现截图:三⼂动态创建实现原理之宏拆开 我们要看实现原理.当然要把宏拆看看看做了什么事情了.1. DECLARE_DYNCREATE 宏拆开#define DECLARE_DYNCREATE(class_name) \DECLARE_DYNAMIC(class_name) \ RTTI动态识别static CObject* PASCAL CreateObject();我们可以看到这个宏包含了我们的RTTI 类型识别. 并且添加了⼀个新的成员函数static Cobject * Createobject();RTTI动态识别.上⼀讲已将讲过了. 就是添加了⼀个 CRuntimeClass 成员.以及获取成员的⽅法. 本次不讲解. 全部解开的宏public:static const CRuntimeClass classCMainWnd; 指针virtual CRuntimeClass* GetRuntimeClass() const; 获取这个指针的函数static CObject* PASCAL CreateObject(); 新增的函数2.实现宏拆开 IMPLEMENT_DYNCREATE#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, NULL)其中还包含了⼀个宏 IMPLEMENT_RUNTIMECLASS也进⾏拆开.#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) \AFX_COMDAT const CRuntimeClass class_name::class##class_name = { \#class_name, sizeof(class class_name), wSchema, pfnNew, \RUNTIME_CLASS(base_class_name), NULL, class_init }; \CRuntimeClass* class_name::GetRuntimeClass() const \{ return RUNTIME_CLASS(class_name); }第⼀个宏 IMPLEMENT_DYNCREATE 其实就是对 CreateObject进⾏实现. 也就是返回⾃⼰本⾝的创建的类第⼆个宏就是对⾃⼰本⾝的结构体成员进⾏初始化.并且实现虚函数获取⾃⼰的这个成员. 跟RTTI⼀样.只不过初始化的时候.结构体初始化的值不⼀样.也就是我们上⾯说的CRuntimeClass结构中的新增的两个成员进⾏了赋值.解析的代码//IMPLEMENT_DYNCREATE(CMainWnd,CFrameWnd)CObject* PASCAL CMainWnd::CreateObject(){return new CMainWnd;}const CRuntimeClass CMainWnd::classCMainWnd ={"CMainWnd", sizeof(class CMainWnd), 0xFFFF, CMainWnd::CreateObject, 添加了⾃⼰的成员函数指针.其余地⽅⼀样这个函数指针创建⾃⼰本⾝对象并且返回.RUNTIME_CLASS(CFrameWnd), NULL, NULL};CRuntimeClass* CMainWnd::GetRuntimeClass() const{return RUNTIME_CLASS(CMainWnd);}所以远离就是CRuntime⾥⾯添加⾃⼰创建对象的函数指针. 然后⾃⼰的类中实现这个函数.创建⾃⼰的对象并且返回这个就是动态创建了.。

MFC笔记

MFC笔记

GetDlgItem:根据ID获取一个子窗口的对象地址(包含窗口句柄) GetDlgItemText和SetDlgItemText:根据ID获取或设置一个子窗口标题文字 GetDlgItemInt和SetDlgItemInt:根据ID获取或设置一个子窗口内显示的数字 GetDlgCtrlID和SetDlgCtrlID:根据窗口对象内的句柄获取或设置该窗口的ID GetParent和IsChild:这两个函数是等价的 GetWIndow: GetNextWIndow:
InitDialog函数用于初始化对话框中的子控件,可操作子窗口 Create函数主要用于 通用窗口的创建函数,如菜单、工具条等,窗口还未显示出来, 只有父窗口,子窗口还没创建 在非模式对话框中: 在使用EndDialog函数关闭时,只有隐藏没有真正关闭 使用DestroyWindow函数进行真正关闭
3—4讲,24分18秒
系统消息和非系统消息
• 系统消息编号:1—WM_USER-1 • 非系统消息:消息编号要大于1024,主要 用于传递数据
SendMessage函数和PostMessage函数的区别: 二者的功能: 能够向指定的窗口发送窗口消息,既可以是本进程内窗口 也可以是其它进程的 可以发送系统和非系统消息 SendMessage是阻塞型函数,用于调用指定窗口的内部程序,直到窗口 程序处理完毕后再返回 是非阻塞型函数,是将一个消息寄送到指定窗口内的消息 队列后立即返回
步骤如下: 1.定义自己的消息宏,如UM_ADD等,消息编号必须是大于 WM_USER,因为从1到WM_USER是系统消息; 2.自动添加消息处理函数 3.将“自定义的消息宏”和“消息处理函数”绑定,利用ON_ MESSAGE宏实现; 4.添加自己的代码,实现具体的功能

深入浅出MFC学习笔记(第三章:MFC六大关键技术之仿真:命令传递)

深入浅出MFC学习笔记(第三章:MFC六大关键技术之仿真:命令传递)

软件英才网软件行业驰名招聘网站命令传递(Command routing)消息如果是仅仅从派生类流向父类,那就非常简单了。

然而MFC用来处理消息的C++类,并不是单线发展的。

document/view也具有处理消息的能力。

因此,消息应该有横向流动的机会。

MFC对消息循环的规定为:1:若是一般的windows消息(WM_xx)则一定是由派生类流向基类。

2:如果是WM_COMMAND消息,就非常复杂了。

要区分接受者的类型:1:接受者若为Frame窗口:处理次序为:View-> Frame窗口本身->CWinApp类。

2:接受者若为View :处理次序为:View本身->Document;3:接受者若为Document:处理次序为:Document本身->Document template软件英才网软件行业驰名招聘网站因此,接下来我们的任务就是仿真以上的消息传递路线。

以下为需要添加的函数:全局函数AfxWndProc,它是整个消息循环的起始点,本来应该在CWinThread::Run中被调用,每调用一次就推送一个消息。

模拟windows的disPatch函数。

软件英才网软件行业驰名招聘网站LRESULT AfxWndPro(HWND hWnd,UINT nMsg,WPARAMwParam,LPARAM lParam,CWnd *pWnd) {cout<<"AfxWndProc()"<<endl;return AfxCallWndProc (pWnd,hWnd,nMsg,wParam,lParam); }LRESULT AfxCallWndProc(CWnd*pWnd,HWND hWnd,UINT nMsg,WPARAM wParam,LPARAM lParam)软件英才网软件行业驰名招聘网站{cout<<"AfxCallWndProc"<<endl;LRESULT lResult=pWnd->windowProc(nMsg,wParam,lParam);return lResult;}全局函数AfxCallWndProc用于调用接受消息的类的消息处理函数。

MFC编程学习心得

MFC编程学习心得

//1、将C语言变量简单重新定义UINT、INT(32位,4字节)LONG、DWORD(32位,4字节)WPARAM、LPARAM(32位,4字节)SHORT、WORD(16位,2字节)LONG、LRESULTBOOL(TRUE、FALSE)PINTPSTR、LPSTR、LPCSTR(字符串指针,只读和可写)//2、H开头,Windows句柄类型变量HANDLE of Windows =>HWNDHANDLE of Instance =>HINSTANCEHANDLE of Icon =>HICON//3结构体类型SIZE、POINT、RECTMFC所有封装类一共有200多个,但是MFC的内部技术不只是简单地封装。

MFC内部总共有六大关键技术,构架起了整个MFC开发平台。

一、MFC的六大关键技术包括:a)MFC程序的初始化过程:b)消息映射机制;c)运行时类型识别(RTTI);d)动态创建;e)永久保存;f)消息传递;六大关键技术的目的是为了提高开发效率,开发者只需要在局部做简单的修改,即可处理大部分窗口事物。

二、SendMessage和PostMessage函数的功能:a)能够向指定的窗口内发送窗口消息,既可以是本进程内窗口也可以是其他进程的;b)既可以发送系统内部消息,消息编号的范围是:1-WM_USER-1;例如:WM_LBUTTONDONW,WM_MOUSEMOVE等;c)也可以发送非系统消息(开发者定义的消息),范围是WM_USER-0x7FFF。

三、SendMessage和PostMessage两个函数的区别是:a)SendMessage是阻塞型函数,PostMessage是非阻塞型函数:SendMessage用于调用指定窗口的内部程序,直到窗口程序处理完成以后再返回:PostMessage是将一个消息寄送到一个窗口内的消息队列后就立即返回。

b)两个函数的返回值不同:LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM,lParam);BOOL PostMessage(HWND hWnd,UNIT Msg,WPARAM wParam,LPARAM,lParam); SendMessage的返回值依赖于消息处理函数c)跨线程或者跨进程发送消息,推荐使用PostMessage函数。

MFC原理系列报告之运行期类型识别

MFC原理系列报告之运行期类型识别

MFC原理系列报告之:运行期类型识别一总论刚学习完MFC,一时心血来潮,分析下MFC的几个关键技术,算是对学习的总结。

由于本人还是个初学者,能力有限,语言组织欠妥,肯定有不足之处,欢迎批评斧正。

有以下几个部分内容:1.RTTI(运行期类型识别)2.动态创建3.序列化的实现4.程序的产生,运行和结束,以单文档框架程序为例5.单文档框架程序/类型之间的关系6.MFC消息机制的流转7.实现自己的SPY ++二: RTTI, 动态创建,序列化RTTI是动态创建的基础,序列化同时用到动态创建和RTTI,所以RTTI 是MFC的基石。

三者的关系很紧密。

.1.动态创建可以简单理解为,通过字符串创建对象。

比如你封装了一个类CLine,如何仅仅通过字符串“CLine”创建来CLine类的对象。

2.序列化是指从持久存储介质中读出或写入一个对象的过程。

举个例子:在一个CAD系统里,用户画了一些线条呀,矩形等等。

如何将当前所有图形保存到文件中,下次打开文件,然后正确读取并显示出来。

让我们尝试分析下,假设有两个类CLine, CRectangle分别负责绘制线条和矩形。

CLine里保存线条的起始坐标点。

Crectangle保存矩形的左上角坐标点,以及右下角坐标点。

用户每画一个线条,则创建一个CLine对象,矩形也是如此。

当用户保存线条到文件时,需要保存哪些内容呢?肯定要有CLine的类型信息,类信息至少有类的名字。

如果不保存,读取图形文件时,无法创建一个CLine对象,也就不能再正确显示出来。

读出对象时,根据字符串“CLine”创建一个CLine对象,即动态创建。

这里保存和读取对象的过程就是序列化,很显然序列化需要动态创建的支持,但是二者共同基础却是RTTI。

三. RTTI详解RTTI (Run_Time Type Identification),即运行期类型识别,是MFC动态创建的基础,可以对类型进行管理,对类型之间的关系,对象的类型进行识别和检查。

孙鑫深入详解MFC学习笔记

孙鑫深入详解MFC学习笔记

Windows编程一、#define的几个注意点①#与##的用法;#xxx将后面的参数xxx字符串化xxx##yyy,将两个参数连接②\ 的用法一行结束使用,表示一行未结束。

二、函数调用约定_stdcall_stdcall是Pascal方式清理C方式压栈,通常用于Win32 Api中,函数采用从右到左的压栈方式,堆栈由它自己清理。

在win32应用程序里,宏APIENTRY,WINAPI,都表示_stdcall,非常常见。

相对应的_cdecl,堆栈由main()函数或者其他函数清理。

C和C++程序的缺省调用方式则为__cdecl,下图为VC++6.0的默认设置,因此在不显式写明调用约定的情况下,一般都是采用__cdecl方式,而在与Windows API打交道的场景下,通常都是显式的写明使用__stdcall,才能与Windows API保持一致。

另外,还要注意的是,如printf此类支持可变参数的函数,由于不知道调用者会传递多少个参数,也不知道会压多少个参数入栈,因此函数本身内部不可能清理堆栈,只能由调用者清理了。

三、防止头文件重复包含----预编译在写好的类的首位加上预编译代码,例如:#ifndef xxx_h#define xxx_hClass xxx{...};#endif四、HDC、CDC、CClientDC、CWindowDCHDC是平台SDK提供的全局类,与设备上下文相关CDC则是类似于封装在CWnd中的一个HDC。

CClientDC:继承于CDC,构造函数完成获取DC,析构函数完成释放DC。

CWindowDC:继承于CDC,构造函数完成获取DC,析构函数完成释放DC,在整个窗口上绘图CMetaFileDC:图元文件设备描述环境类创建:CMetaFileDC dc;dc.Create();接下来用一般dc的绘图操作,绘图的内容均会保存至图元文件中;HMETAFILE m_hMetaFile=dc.Close(); //图元文件赋予数据成员显示图元文件:用一般dc的PlayMetaFile(m_hMetaFile)显示图元文件窗口销毁时删除图元文件SDK函数::DeleteMetaFile(m_hMetaFile)五、OnDraw函数、OnCreate函数OnDraw函数:窗口重绘的时候被框架类FrameWnd调用,响应WM_PAINT消息。

深入浅出MFC学习笔记(第三章MFC六大关键技术之仿真类

深入浅出MFC学习笔记(第三章MFC六大关键技术之仿真类

第三章: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;##用来告诉编译器把两个字符串连接起来。

追根究底剖析MFC六大关键技术收藏

追根究底剖析MFC六大关键技术收藏

追根究底,剖析MFC六大关键技术(第一部分)收藏追根究底,剖析MFC六大关键技术题外话:我并不认为MFC减轻了程序员们的负担,MFC出现的目的虽然似乎是为了让程序员不用懂得太多就可以进行视窗编程,但本人在MFC 里徘徊了很久很久(因为那时没有书本详细介绍MFC的原理),毫无收获。

可能朋友们会说,怎么一定要了解MFC的具体呢,“黑箱”作业不行吗?这不是微软的初衷吗?不行!!!如果这样,我宁愿永远不选择MFC!在学电脑之前,本人学习的东西大都与艺术不无关系,小学时参加过全国书画比赛获银奖。

儿时的爱好就是在一张纸上随心所欲地画画!MFC“黑箱”就象一幅硕大的抽象画(抽象到你不能理解),它用铅笔勾画好线条,然后请你填颜色。

我们怎么能忍受“黑箱”作业?我们选择C++,就是因为它够自由,够艺术,我们可以在此放飞幻想。

所以,我们要攻克MFC。

伟大孙老师在剖析MFC的时候虽然尽心尽力,但可能由于篇幅所限,说得并不大清楚(我相信许多学员都有这方面的感受)。

在此,我突发奇想,想与大家一同分享一下著名的MFC六大关键技术。

从什么地方开始讲起好呢?我觉得回到最初摸索MFC的时候,从基本谈起最好。

因为我知道,一个走过来程序员,总是忘记了当初自己是怎么走过来的,忘记了一个学员最想知道的是什么。

一个小小的问题(一两句话就可以解释的),足学以令手无寸铁的学员头大半个月,所以,我努力回忆当初是怎么让自己豁然开朗的。

转入正题:MFC的六大关键技术包括:MFC程序的初始化过程。

运行时类型识别(RTTI)。

动态创建。

永久保存。

消息映射。

消息传递。

MFC程序的初始化过程1、设计一个简单完整MFC程序,产生一个窗口。

当然这不能让AppWizard自动为我们生成。

我们可以在Win32 Application工程下面那样写:#include <afxwin.h>class MyApp : public CWinApp{public:BOOL InitInstance() //②程序入点{CFrameWnd *Frame=new CFrameWnd();//构造框架m_pMainWnd=Frame; //将m_pMainWnd设定为Frame;Frame->Create(NULL,"最简单的窗口");//建立框架Frame->ShowWindow(SW_SHOW); //显示框架return true; //返回}};MyApp theApp; //①建立应用程序。

  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函数。

相关文档
最新文档