文章导读:在新的一年中,各位网友都进入紧张的学习或是工作阶段。网学的各位小编整理了ASP.net-Visual C++.NET编程讲座之二的相关内容供大家参考,祝大家在新的一年里工作和学习顺利!
第1讲 从MFC"类"开始
摘要
本讲先来通过一个简单的MFC应用程序来介绍"类"的有关概念,然后分析其运行机制以及基本MFC类层次结构,最后使用项目模板所提供的MFC应用程序向导来创建一个单文档程序TextViewer。
一个简单的MFC应用程序
在现在的"面向对象"程序设计中,我们经常会听说过"类"和"对象"的概念。那么什么是"类"呢?"类"的实质上是一种新的复杂数据类型。说它"新",是因为它不同于C语言中的char、int、float等基本数据类型,说它"复杂",是因为它不仅可以包含各种基本类型的数据,而且还可以包含处理这些数据的函数。
MFC使用"类"来编写Windows应用程序,例如下面的过程:
(1) 单击"开始"页面中的"新建项目",或者打开"文件"菜单中的"新建",选择"项目"命令,都将弹出"新建项目"对话框。
(2) 在左侧的"项目类型"窗格中,选中"Visual C++项目"。在右侧的"模板"窗格中,拖动窗格右侧的滚动条显示其他模板,然后选中"Win32 项目"。
(3) 在"名称"文本框中,输入项目名称"Ex_1_SimpMFC",单击"确定"按钮,弹出"Win32 应用程序向导"对话框。
(4) 单击左侧的"应用程序设置"。选中"应用程序类型"中的"Windows 应用程序",在"附加选项"中选中"空项目",结果如图1所示,单击"完成"按钮。
图1 Win32 应用程序设置
(5) 在"解决方案资源管理器"中,右击项目名称Ex_1_SimpMFC,从弹出的快捷菜单中选择"添加",然后选择"添加新项",弹出"添加新项"对话框。
(6) 在右侧的"模板"窗格中选中"C++文件",在"名称"文本框中输入SimpMFC,单击"打开"按钮。
(7) 键入如图2所示的代码。
(8) 在"解决方案资源管理器"标签中,右击顶层的项目名"Ex_1_SimpMFC",从弹出的快捷菜单中选择"属性"菜单项,弹出如图3所示的"Ex_1_SimpMFC 属性页"对话框。
(9) 单击"MFC的使用",然后单击右边的下拉按钮,从弹出的下拉选择列表选择"在共享DLL中使用MFC",单击"确定"按钮。
(10) 打开"调试"菜单,选择"开始执行(不调试)",或按Ctrl + F5,运行程序,结果如图4所示。
运行机制及MFC类结构
1.代码分析
在图2中,包含文件afxwin.h是使用MFC类库的头文件。class是定义类的关键字,class的后面是用户定义的类名,即CSimpApp。需要说明和是:通常用大写的C字母开始的标识符作为类名,C用来表示类(Class),以与函数及其他数据类型相区别。
类体中定义的函数或变量,都称为该类的"成员",其中变量称为"成员变量",函数称为"成员函数"。成员可被声明成public、private。对于public类成员来说,它们是公有的,能被类外面的程序访问;对于private类成员来说,它们是私有的,只能由类中的函数所使用,而不能被外面的程序所访问。
在"public:"或"private:"后面定义的所有成员都是公有或私有的,直到下一个"public:"或"private:"出现为止。若成员前面没有类似"public:"或"private:"的声明,则所定义的成员是private(私有),这是类的默认处理。关键字public和private可以在类中出现多次,且前后的顺序没有关系。
类名冒号后面的是用来定义类的继承,其格式如下:
class 派生类名 : 继承方式 基类名
{
派生类的成员
};
其中,被继承的类称为基类(base class),在基类上建立的新类称为派生类(derived class)。继承方式有三种:public(公有)、private(私有)及protected(保护),若继承方式没有指定,则被指定为缺省的public方式。继承方式决定了派生类的继承基类属性的使用权限,public继承方式能够使用基类的所有共有成员。
从代码中可以看出,类CSimpApp是从应用程序类CWinApp派生而来。而类CMainFrame是从框架窗口类CFrameWnd派生而来。
在面向对象的程序设计中,类有函数重载、运算符重载和虚函数等,这些称为类的多样性。
所谓"函数重载",是指在类中或同一个作用域中,允许有多个同名的函数存在,但同名的各个函数的形参必须有区别:形参的个数不同,或者形参的个数相同,但参数类型有所不同。
所谓"运算符重载",就是赋予已有的运算符多重含义。
所谓"虚函数",它是指在函数名前面加上virtual关键字的成员函数,如成员函数InitInstance就是被声明成了虚函数。虚函数也是能使一个函数具有多种不同的版本,只不过虚函数的不同版本是在基类和派生类中进行定义的。这样系统就会根据相应的类对象来决定调用的是派生类CSimpApp的InitInstance()函数中的代码,还是基类InitInstance()函数中的代码。
在CMainFrame类中,我们还看到了与该类名相同的成员函数CMainFrame(),这个函数称为该类的"构造函数"。每个类都有一个构造函数,如果我们没有指定,系统就会自动使用默认的构造函数。构造函数的最大特点是在对象建立时它会被自动执行,因此用于变量、对象的初始化代码一般放在构造函数中。在定义构造函数时,不能指定函数返回值的类型,也不能指定为void类型。
在CMainFrame()构造函数中的Create函数是用来创建窗口,它的参数依次用来指定类名、窗口标题、窗口样式和窗口大小。其中,预定义样式WS_OVERLAPPEDWINDOW用来创建一个常规窗口,CRect是一个矩形的数据类,用来确定窗口的大小和位置。
与构造函数相对应的是析构函数。析构函数是另一种特殊的C++成员函数,它只是在类名称前面加上一个"~"符号。每一个类只有一个析构函数,没有任何参数,也不返回任何值。
在类定义时,成员函数既可以在类中定义,也可以在类外定义。但在类外定义时,必须用作用域运算符"::"来通知编译系统该函数所属的类。例如,InitInstance函数就是在类CSimpApp外面定义的。
代码中,m_pMainWnd是MFC中的一个全局指针变量。MessageBox()是窗口基类CWnd的一个成员函数,用来弹出一个对话框窗口,显示参数指定的短信息,这里是"你好,欢迎进入MFC世界!"。
2.运行机制
在程序中,当定义一个类对象时,它会自动调用相应的构造函数。所谓"类对象",就是用该类定义的"变量",这个"变量"又称为类的一个实例。例如,theApp就是类CSimpApp的一个对象。
MFC正是利用类的这种"自动调用相应的构造函数"特性,使得WinMain()函数的调用变成了应用程序框架内部的调用,所以我们在代码中看不到每个Windows程序所必须有的WinMain()函数。
当应用程序运行到"CSimpApp theApp;"时,系统就会先调用基类CWinApp构造函数,进行一系列的内部初始化操作,然后自动调用CSimpApp的虚函数InitInstance(),该函数会进一步调用相应的函数来完成主窗口的构造和显示工作。下面来看看上述程序中InitInstance的执行过程。
首先执行的是:
m_pMainWnd = new CMainFrame;
该语句用来创建从CFrameWnd类派生而来的用户框架窗口CMainFrame类对象,继而调用该类的构造函数,使得Create函数被调用,完成了窗口创建工作。
然后执行后面两句:
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
用作窗口的显示和更新。接下来调用:
m_pMainWnd->MessageBox("你好,欢迎进入MFC世界!");
最后返回TRUE,表示窗口创建成功。
由于应用程序类CWinApp是用来调用WinMain以及实例的初始化,因此每一个MFC应用程序有且只能一个这样的应用程序类,且需要一个全局的对象实例,如上述程序中的theApp,当然也可换一个对象名。
InitInstance()完成初始化工作之后,接下来就是调用基类CWinApp的成员函数Run(),执行应用程序的消息循环,即重复执行接收消息并转发消息的工作。当Run()检查到消息队列为空时,将调用基类CWinApp的成员函数OnIdle进行空闲时的后台处理工作。若消息队列为空且又没有后台工作要处理时,则应用程序一直处于等待状态,一直等到有消息为止。
当程序结束后,调用基类CWinApp的成员函数ExitInstance(),完成终止应用程序的收尾工作。这就是MFC应用程序的运行机制。
3.MFC类结构
Visual C++发展至今,MFC类库越来越强大,其基本层次结构如图5所示,箭头的方向是从派生类指向基类。
其中,CObject类是MFC提供的绝大多数类的基类。该类完成动态空间的分配与回收,支持一般的诊断、出错信息处理和文档序列化等。
CCmdTarget类主要负责将系统事件(消息)和窗口事件(消息)发送给响应这些事件的对象,完成消息发送、等待和派遣(调度)等工作,实现应用程序的对象之间协调运行。
CWinApp类是应用程序的主线程类,它是从CWinThread类派生而来。CWinThread类用来完成对线程的控制,包括线程的创建、运行、终止和挂起等。
CDocument类是文档类,包含了应用程序在运行期间所用到的数据。
CWnd类是一个通用的窗口类,用来提供Windows 中的所有通用特性。
CView 是用于让用户通过窗口来访问文档以及负责文档内容的显示。
CFrameWnd 类是从 CWnd 继承来的,并实现了标准的框架应用程序。
CDialog 类用来控制对话框窗口。
CMDIFrameWnd和CMDIChildWnd类分别用来多文档应用程序的主框架窗口和文档子窗口的显示和管理。
CMiniFrameWnd类是一种简化的框架窗口,它没有最大化和最小化窗口按钮,也没有窗口系统菜单,一般很少用到它。
使用MFC应用程序向导
事实上,在Visual C++ .NET中,我们不需要输入上述程序代码,甚至不需要输入一句代码就能创建所需要的应用程序,这就是MFC各种项目模板中的应用程序向导(MFC AppWizard)的功能,如下面的过程。
(1) 单击"开始"页面中的"新建项目",或者打开"文件"菜单中的"新建",选择"项目"命令,都将弹出"新建项目"对话框。
(2) 在左侧的"项目类型"窗格中,选中"Visual C++ 项目"。在右侧的"模板"窗格中,拖动窗格右侧的滚动条显示其他模板,然后选中"MFC应用程序"。
(3) 在"名称"文本框中,输入项目名称TextViewer。
(4) 单击"确定"按钮 ,弹出"MFC应用程序向导"对话框。
(5) 单击左侧的"应用程序类型",出现如图6所示的页面。在这里,我们可以选择不同的应用程序类型、项目样式以及MFC使用的是静态还是共享DLL(Dynamic Link Library,动态链接库)。需要说明的是,一定要选中"文档/视图结构支持",否则文档程序中常用的磁盘文件的打开、保存以及文档和视图的相互作用等功能都需要用户来实现。
图6 应用程序类型
需要说明的是:在MFC应用程序框架中,最基本的四种应用程序类型有:单文档、多文档、多顶级文档和基于对话框的应用程序。
单文档应用程序是类似于Windows记事本的程序,它的功能比较简单,每次只能打开和处理一个文档。它的复杂程度适中,虽然每次只能处理一个文档,但已能满足一般工程上的需要。因此,大多数Windows桌面应用程序的编制都是从单文档程序框架开始的。
基于对话框的程序最简单,也最紧凑的。它没有菜单、工具栏及状态栏,也不能处理文档,但它的好处是速度快,代码少,程序员所花费的开发和调试时间短。
多文档应用程序,顾名思义,能允许同时打开和处理多个文档。它增加了许多功能,因而需要大量额外的编程工作。
多顶级文档应用程序与多文档应用程序功能相似。所不同的是,多文档应用程序打开的多个文档出现在同一个窗口的客户区内,而多顶级文档应用程序打开的多个文档出现桌面上,每个文档都会在任务栏上有其相应的工具条,这与Microsoft Office 2000/XP的文档操作相同。
(6) 选中"单文档",单击左侧的"用户界面功能",弹出如图7所示的页面。在这里我们可以改变对浮动工具条、主框架和子框架窗口的样式等特性的支持。
(7) 单击左侧的"高级功能",弹出如图8所示的页面。在这里我们可以改变对添加对上下文帮助、自动化、打印与预览、通信等特性的支持,以及设置最近文件列表中的文件数。
(8) 单击左侧的"生成的类",弹出如图9所示的页面。在这里我们可以改变对对MFC 应用程序向导提供的默认类名、基类、各个源文件名进行修改。
图9 生成的类
(9) 单击"完成"按钮,一个单文档应用程序项目TextViewer就创建好了。运行程序,结果如图10所示。
结束语
在向导中,除了前面到的特性外,还对"数据库"以及资源模板字符串和复合文档的支持等。总之,使用项目模板的MFC应用程序向导可以创建最常用的应用程序类型。当然,向导创建的应用程序中的各个类之间还存在着紧密联系,在下一讲中,我们将根据各个类的关联机制,讨论文档数据是如何读取并显示的。