1、研发二部2015年6月 杭州长川科技股份有限公司新员工入职培训之MFC编程基础第一部分 基础知识 1.MFC的英文全称是Microsoft Foundation Classes,即微软的基础类库。MFC的本质就是一个包含了许多微软公司已经定义好的对象的类库。2.虽然开发人员要编写的程序在功能上各有不同,但是从结构上讲,都可以化分为对用户界面的设计、对文件的操作、对数据库的访问及对多媒体的使用等一些最主要的方面。这一点正是微软提出MFC类库最重要的原因。3.在MFC类库中,大约有200个类。在进行程序设计时,只需简单地调用已有的类及类中的方法即可。另外,还可以利用“继承”方法从已有类中派生出自己
2、想要的类。这时,派生出来的类不但拥有父类中的方法和属性,还可以根据自己的需求,自定义一些特殊的属性和方法,使得派生类功能更加强大。MFC有较好的移植性,可应用于众多平台MFC概述MFC类库结构nMFC中类可划分为基类、应用程序结构类、窗口类、OLE类、数据库类等10大类,而且在其中的一些大类的基础上又派生出许多子类。MFC的类库结构的层次图如下图所示。MFC类库结构n从上图中可以看出,CObject是一个原始基类。绝大多数MFC类的最终基类都是CObject。原始基类下面,主要包括以下几种类:MFC应用程序结构类,窗口、对话框和控件类,输出(设备文本)和绘图类,简单数据类型类,数组、列表和映射
3、类,文件和数据库类,Internet和网络类,OLE类以及高度和异常类。nMFC的应用程序结构类分为CWinApp和CWinThread。使用MFC创建的每一个应用程序都包含一个由类CWinApp派生而来的应用程序对象。该对象是一个全局对象。应用程序对象主要用于处理应用程序的初始化,同时也处理应用程序事件的消息循环。nCCmdTarget和CCmdUI为MFC中常用的有关发送命令的类。CDocument为MFC中常用的应用程序文档的基类。CDocTemplate为文档模版类,通常是应用程序的单文档或多文档的基类。CView类是常用的视图类。C+语言基础n要使用Visual C+进行Window
4、s应用程序的开发,就要掌握面向对象的思想和C+语言。本章先讲述一个简单的C+程序,然后根据这个程序,向读者介绍C+中语言基础。C+的基本数据类型及数据n数据类型是对数据的一种抽象描述。在计算机程序中能操作的数据有很多种,不同的数据所需要的存储空间有所不同。将数据按照类型进行分类,有助于程序员对于存储空间的分配。本节将具体介绍有关C+中的数据及其所属的数据类型。变量n变量是一种特殊的标识符,在变量中可以存储数据。变量中存储的数据可以根据程序的需要而改变,因此称为变量。n1定义变量n在C+中,使用一个变量必须先定义该变量。C+中定义变量的语法代码如下:n定义一个变量需要说明两点,一是变量的类型,二
5、是变量的名称。其中,变量的类型是C+中的数据类型。变量名是用户为变量起的名称。变量nC+的变量名由字符及数字等组成。变量名必须满足以下几个条件。n变量名只能由字母、数字和下划线(_)组成。n变量名必须以字母或下划线开头。n变量名不能包含空白字符(换行符、空格和制表符称为空白字符)。n变量名不能与保留字名相同。n变量名区分大小写。变量n2变量赋值n如果想要使用一个变量,就要为其进行赋值。如果没有对定义的变量赋值,Visual C+会为该变量默认一个值。例如,如果是一个int类型的变量且没有赋值,Visual C+将默认其值为0。nC+中为变量赋值的方法有两种:一种是在定义变量的同时赋值,另一种是
6、在定义变量后赋值。n在定义变量的同时赋值,代码如下:n在定义变量后赋值,代码如下:常量n常量与变量相反,是一个不随时间和程序变化而变化的值。C+中,常量的命名规则和变量的大体相同。不同的是,常量名称中的字母都为大写。nC+中定义符号常量的语法代码如下:n例如,在计算圆形面积的时候,经常用到PI。为了避免重复地输入PI的实际取值,而用下面的形式声明PI的取值。n这样,在程序中编译时,会将程序中出现的所有字符串PI全部置换成3.14。如果想要修改程序中PI的值,只需在头文件处修改,全部PI的取值都会发生变化。常量nC+中定义静态常量的语法代码如下:n在C+中,同声符号常量一样,在声明静态常量时,也
7、要对其进行初始化,代码如下:n注意:在符号常量中,PI没有类型,不占有存储单元,且容易出错。而在Const常量中,PI有数据类型,并且占有存储单元,有地址,因此可以使用指针指向它。C+的运算符及表达式n运算符和表达式是一种程序语言的基础。运算符的作用是操作变量或表达式。C+中的运算符包括赋值运算符、算术运算符、逻辑运算符、关系运算符、位运算符、逗号运算符、条件运算符等。本节将介绍这些运算符及其所组成的表达式。表达式n表达式是C+程序中不可缺少的一部分。表达式是由运算符、操作数(变量、常量或函数等)和标点符号,按照一定规则组成的一个有意义的语句。例如:运算符C+中的运算符就是一种符号,该符号可以
8、用于处理数据。平时有数学计算中所使用的“+”、“-”、“”、“”都属于运算符。只是这些运算符在C+中的表现形式可能与日常生活中有所不同。下面将对C+中的运算符作具体介绍。1赋值运算符赋值运算符是用于为变量或常量指定数值的运算体符。其操作符号为“”,示例代码如下:上述表达式的意义是,把b的值赋值给a。其中,b可以是一个单纯的变量,也可以是一个表达式。运算符n2算术运算符n算术运算符是用于进行数学运算的运算符。例如,加、减、乘、除等就是算术运算符。操作完成后,返回一个数字型的值。算术运算符包括加法运算符(+)、减法运算符(-)、乘法运算符(*)、除法运算符(/)、模运算符()。n上述算术运算符都是
9、二元运算符,该运算符两端的数据必须是数字。运算符n3逻辑运算符n逻辑运算符,即用于处理逻辑值的运算符。逻辑运算符通常用在条件判断语句或循环语句中,如if、while语句等。C+中的逻辑运算符包括逻辑与运算符(&)、逻辑或运算符(|)、逻辑非运算符(!)。由逻辑运算符构成的表达式,称为逻辑表达式。逻辑表达式的返回值为逻辑值(true或false),一般情况下,1代表true,0代表false。n逻辑与运算符可以进行与操作,其操作方法为:如果逻辑与运算符前的数为false(或是可以得出false的逻辑表达式),则返回false,否则返回true;当逻辑与运算符前后两个数都为true时,才返回tru
10、e。n逻辑或运算符可以进行或操作,其操作方法为:只要逻辑或运算符前后的数据中有一个为true(或是可以得出true的逻辑表达式),则返回true;当逻辑或运算符前后两个数都为false时,才返回false。n逻辑非运算符要求要操作的数据必须是逻辑值,或是能够转换成逻辑值的逻辑表达式。逻辑非运算符可以进行非操作,其操作方法为:如果要操作的数据为true,则返回false;如果要操作的数据为false,则返回true。运算符n4关系运算符n关系运算符,即用于比较两个数据关系大小的运算符,并根据比较的结果返回一个逻辑值。关系运算符包括大于运算符()、大于等于运算符(=)、小于运算符()、小于等于运算
11、符(”一起使用。使用cin的语法代码如下:n例如,想要从键盘输入一些数据,将使用下述代码:n如果想要一次性输入多个数据,不是使用逗号作为分隔符,而应该用“”分隔,应该写成:C+的输入输出n2输出语句nC+的输出语句用cout表示。其中,cout必须和“”一起使用,使用cout的语法代码如下:n例如,想要从键盘输出一些数据,将使用下述代码:n如果想要一次性的输出多个数据,同样不是使用逗号作为分隔符,而是每项数据之间用“”分隔,如上述代码所示。n注意:在C+中,可以不用“n”控件换行,可以使用“endl”进行换行。因为在头文件iostream中定义endl(end of line)代表回车换行,其
12、作用与“n”相同。选择语句n选择语句也称分支语句,即根据不同的条件执行不同的语句。在C+中,主要的选择语句有if语句和switch语句。n1if语句nif语句有三种基本结构。n(1)第一种基本结构的语法如下:n执行该if语句时,首先判断表达式是否正确。如果正确,则执行语句1。如果不正确,则不执行任何操作,执行if语句后的其他语句。该语句流程如右图所示。选择语句n(2)第二种基本结构的语法如下:n执行该if语句时,首先判断表达式结果是否为真。如果判断结果为真,则执行语句1。如果判断结果为假,则执行语句2。该语句流程如右图所示。选择语句n(3)第三种基本结构的语法如下:n执行该if语句时,首先对表
13、达式1进行判断。如果判断结果为真,则执行语句1。如果判断结果为假,则对表达式2进行判断。如果表达式2的判断结果为真,则执行语句2。否则,执行语句3。该语句的流程图如右图所示。选择语句n2switch语句nC+中的另外一种选择语句是switch语句,其语法如下:该语句的流程图如右图所示。循环语句n在编写程序的过程中,经常会遇到一些许多有规律性的重复操作,则在程序中需要重复执行这些语句。为此,C+中提供了循环语句,可使代码大大简化。循环语句包括循环条件和循环体两部。C+中的循环语句包括for语句、while语句和dowhile语句。n1for语句nfor语句是使用最频繁并且最灵活的循环语句。其语法
14、代码如下:n其中,表达式1通常用于为循环变量赋初值,表达式2为循环条件,表达式3用于循环变量的递增或是递减,使得循环趋于结束。循环语句nfor语句的执行过程如下:n(1)初始化表达式。n(2)执行循环表达式。如果不满足条件,则跳出循环语句。n(3)如果满足条件,则执行语句块(循环体)。n(4)循环变量递增或递减。n(5)返回步骤(2)。n(6)循环结束,执行for语句下的语句。nfor语句的流程图如右图所示。循环语句n2while语句nwhile语句用于“当满足某一条件时进入循环”的情况,其语法代码如下:nwhile语句的执行过程如下:n(1)判断循环条件。n(2)表达式如果为真,则进入循环体
15、。否则,进入步骤(4)。n(3)执行循环体表达式。n(4)循环结束,执行while语句下的语句。nwhile语句的流程图如右图所示。循环语句n3dowhile语句ndowhile语句和while语句类似,其语句代码如下:ndowhile语句的执行过程如下:n(1)执行循环体语句块。n(2)判断循环条件。如果满足条件,返回步骤(1)。否则,执行步骤(3)。n(3)退出dowhile语句。ndowhile语句的流程图如右图所示。循环语句n从上述代码中可以看出,while语句和dowhile语句的区别:n(1)从结构上看,while语句的循环条件在前,循环体语句块在后。而dowhile语句的循环体语
16、句块在前,循环条件在后。n(2)while语句的循环条件后没有分号,而dowhile语句的循环条件后有分号,且不能省略。n(3)从执行流程上看,while语句如是不满足循环条件,会直接跳过该循环。而dowhile语句是无条件地执行一次循环体语句块。其他语句n在循环语句中,经常用到一些语句,如break、continue和goto语句等。下面对这些语句做简单介绍。n1continue语句ncontinue语句是跳过循环体中剩余的语句而强制执行下一次循环。其作用为结束本次循环,即跳过循环体中下面尚未执行的语句,接着进行下一次是否执行循环的判定。ncontinue语句只能用于循环语句中,通常与if语
17、句配合使用。n2break语句n当程序运行到break语句时,立即结束break语句所在的整个循环,转向循环语句下面的语句继续执行。n3goto语句ngoto语句为无条件转向语句,通常与条件语句配合使用。但其易使程序流程混乱,一般不建议使用。所以在此不过多介绍。C+的面向对象的面向对象面向对象技术是当今软件开发的主流,很多开发人员都转向使用面向对象的语言进行编程。而C+也是面向对象程序设计语言的一种。本章将依次讲解C+中的类与对象。内容包括类与对象、类的继承与派生、类的多态性等。类与对象n客观世界中,任何一个事物都可以看成是一个对象(Object)。在C+中,对象的类型被称为类(class)。
18、本节将具体介绍类与对象的相关概念与使用。面向对象的思想n面向对象的思想和面向过程的思想是相对的。面向过程的程序,详细地描述了每一时刻的数据结构及对其的操作过程。而面向对象的程序,将一个个小的操作封装成对象。在以后的编写中,只需调用对象即可。面向对象的程序有三大特性:封装性、继承性与多态性。面向对象的思想n1封装性封装性n所谓的封装性,有着两方面的含义:一是将基本数据和对此数据进行操作的过程和函数结合起来,形成一个对象,各个对象之间相互独立,互不干扰。二是对象将对外界公开的是一个界面,将具体的细节隐藏起来,保证了数据的安全性。n2继承性继承性n继承性是面向对象程序设计中最重要的机制。通过继承机制
19、,可以方便地利用一个已有的类(父类)建立一个新的类(子类)。新类不但可以继承已有类的属性和方法,还可以拥有自己特有的方法。n3多态性多态性n所谓多态性是当不同的对象收到相同的消息时产生不同的动作。多态性是面向对象程序设计的一个重要特征,其增加了程序的灵活性。类的声明n类是具有相同属性和相同方法的对象的集合。类由类头(class head)和类体(class body)组成。类头由关键字class和类名组成。类体是指花括号()中的内容。类体由数据成员和成员函数组成。需要注意提,类的声明以分号结束。声明类的一般形式为:类的声明n其中,关键字private、public和protected称为成员访
20、问限定符。用这些访问限定符来声明各成员的访问属性。nprivate:只能在本类中访问,在类外不能访问。npublic:既能在本类中访问,又能在类外通过该类的对象进行访问。nprotected:与private类似,不能被类外访问,但能被派生类的成员函数访问。n说明:如果在类的声明中没有使用关键字,则系统将数据成员和函数默认为是私有的。成员函数的定义n在C+中,定义成员函数可以在类中定义,也可以在类外定义。n如例4-1所示,display()是在类中进行声明并且定义。而GetName()和GetAge()只是在类中有声明,并没有进行定义。这种函数的定义代码如下:n则在Student类中,函数Ge
21、tName()和GetAge()的定义如下:类与对象的关系n在现实生活中,每一个实体事物都可以作为一个对象。例如,一部手机、一支铅笔、一本书等。但是有些对象是有着相似性的。n在C+中,将这些有着相似的对象归为一类(class)。类是对象的抽象,而对象是类的实例。在编写程序时,应该先声明一个类,再去实例化若干个同类型的对象。n在一个类中,类的属性指的是类的数据成员,类的行为指的是类的方法。对象的声明和实例化n类是一个抽象的概念,因此在程序中不能直接引用。而是将其实例化成为对象后,通过这个对象来对类进行相关的操作。对象的声明有3种方法。对象的声明和实例化n1先声明类类型,后定义对象先声明类类型,后
22、定义对象n这种声明的语法代码如下:n用这种方式为Student类声明对象:n如果想要一次性为某个类声明多个对象,可以用逗号作为分隔符。类的声明与实例化n2 2在声明类的同时声明对象在声明类的同时声明对象n这种声明的语法代码如下:n用这种方式为Student类声明对象:n如果想要一次性为某个类声明多个对象,可以用逗号作为分隔符。类的声明与实例化n3 3不出现类名,直接声明对象不出现类名,直接声明对象n这种声明的语法代码如下:n如果想要一次性为某个类声明多个对象,可以用逗号作为分隔符。用这种方式为类声明对象:在声明对象之后,可以调用类中的方法。例如,stu1为Student类的一个对象,使用该对象
23、对Student类中的数据成员和函数进行调用。代码如下:构造函数和析构函数n下面介绍C+中两个特殊的函数:构造函数和析构函数。n1 1构造函数构造函数n当声明一个类的属性时,可以不对其进行初始化,因为在C+中有专门的初始化函数对该属性进行初始化。这个专门用来处理对象的初始化的函数就是构造函数。n构造函数是一种特殊的函数。其作用是在完成对象的初始化的同时,将对象的属性初始化。构造函数不需要用户自己来调用它,在创建对象时,由系统自动调用。定义构造函数的语法代码如下:构造函数和析构函数n构造函数的特点如下所述。n构造函数名与类名相同。n构造函数不能指定返回值类型。n构造函数可以有参数,也可以没有参数
24、。n构造函数不能被程序显示调用,只能由系统自动调用。n每个类都必须有一个构造函数。如果在声明一个类时没有给出构造函数的定义,则系统会为该类自动添加一个默认的构造函数。该构造函数的参数列表为空,函数体也为空。类中各属性的值被指定为所属类型的默认值。n构造函数可以重载(有关重载的概念)。也就是说,一个类可以有多个参数不同的构造函数。n注意:当用户为声明的类添加一个自定义的构造函数时,系统则不再为程序添加默认的构造函数。构造函数与析构函数n2 2析构函数析构函数n当一个对象的生命周期结束时,应当去释放该对象所占用的内存空间。这时,系统会自动调用析构函数来进行一些清理工作。定义析构函数的语法代码如下:
25、n析构函数的特点如下所述。n析构函数不允许有返回值。n析构函数不允许有参数。n一个类中有且只有一个析构函数。因此,析构函数不能重载。n对于一个对象来说,析构函数是最后一个被调用的函数。C+类的继承与派生n类的继承是指新的类从已有类中获得已有的特性,例如,数据成员、成员函数等。而从已有类产生新类的过程就称为派生。其中,已有类称为基类或父类,新的类称为派生类或子类。本节将具体绍有关继承与派生的有关知识。派生类的声明n派生类可以将基类中的已有的特性继承下来,也可以添加一些自己特有的新特性。声明派生类的语法代码如下:n从上述代码中可以看出,派生类Student不仅从基类Student中继承了Stude
26、nt类已有的数据成员和成员函数,还新添加了一些自己的数据成员和成员函数。另外,本例中采用的是公有继承。派生类的继承方式n一个类中,其成员的访问权限有public、private和protected之分。而类的继承方式也有三种:公有继承、私有继承和受保护继承。派生类的继承方式n1、公有继承n在声明一个派生类时,将继承方式设为public,则该种继承方式称为公有继承。使用公有继承方式派生出来的类称为公有派生类,其基类称为公有基类。n采用公有方式继承时,基类的公有成员和受保护的成员在派生类中是可以引用的,而其私有成员则不能在派生类中引用。有关公有继承中成员的访问权限如下表所示。派生类的继承方式n2、
27、私有继承n在声明一个派生类时,将继承方式设为private,则该种继承方式称为私有继承。使用私有继承方式派生出来的类称为私有派生类,其基类称为私有基类。n采用私有方式继承时,基类的公有成员和受保护的成员在派生类中相当于是私有成员。而其私有成员不能在派生类中引用。有关私有继承中成员的访问权限如下表所示。派生类的继承方式n3、受保护继承n在声明一个派生类时,将继承方式设为protected,则该种继承方式称为受保护继承。使用受保护继承方式派生出来的类称为受保护派生类,其基类称为受保护基类。n采用受保护方式继承时,基类的公有成员和受保护成员在派生类中相当于是受保护成员。而其私有成员不能在派生类中引用
28、。有关受保护继承中成员的访问权限如下表所示。单一继承和多重继承n在C+中,继承分为两种:单一继承和多重继承。n1单一继承n一个基类只能由一个派生类来继承,这种继承方式称为单一继承。单一继承关系所形成的是一种树形结构,如下图所示。单一继承和多重继承n2多重继承n一个派生类不仅只能拥有一个基类,还可以拥有多个基类,这种继承方式称为多重继承。基于多重继承方式的派生类,同时拥有了多个基类的特性。多重继承的关系如下图所示。n如果已经声明了类A、类B和类C,而类D想要同时成为A、B、C三个类的派生类,即类D是多重继承的派生类。代码如下:C+的多态性n在面向对象的程序中,多态性是一个非常重要的概念。同一操作
29、作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性多态的分类nC+中的多态性是指同一个函数名称对应着功能类似的多个函数。这些函数执行不同但是功能类似的操作,从而实现了“一个接口,多种方法”。C+中的多态性分为两种:静态多态性和动态多态性。n静态多态性是指在编译程序时,系统就能确定所调用的是哪一个函数。因此,静态多态性又称编译时多态性。静态多态性是通过函数重载和运算符重载实现的。n动态多态性是指在程序运行的过程中才能动态地确定调用哪一个函数。因此,动态多态性又称运行时多态性。动态多态性是通过继承和虚函数实现的。运算符重载n所谓重载,就是对一个事物赋予新的含义。而运算符重载,就是
30、对已有的运算符进行重新定义,赋予其另外一种功能,以适应不同的数据类型。运算符重载的语法代码如下:n在C+中,有关重载运算符的规则如下:n只能对C+中已有的运算符进行重载。n并不是C+中的所有运算符都能进行重载,运算符“.”、“:”、“?:”等不能重载。n重载运算符不能改变操作数的个数。n重载运算符不能改变运算符的优先级。n重载运算符不能改变运算符的结合性。n重载运算符不能使用默认参数。虚函数n虚函数是指在派生类中定义与基类同名的函数,但基类中的该函数前有virtual修饰。声明虚函数的语法代码如下:n在C+中,当一个成员函数被声明为虚函数后,其派生类中的同名函数将自动成为虚函数。因此,在派生类中重新声明该虚函数时,virtual可以不加。但为了使程序看起来清晰,一般在派生类中也加上virtual。纯虚函数n在某些特殊情况下,需要使用纯虚函数。例如,有一个动物类,其中有一个名为睡觉的函数。而各种动物的睡觉方式是不同的。此时,可以将动物类中的睡觉函数声明为纯虚函数,而该动物类则成为了抽象类。n声明纯虚函数的语法代码如下:n纯虚函数没有函数体。n语法代码后面的“0”不是代表该函数的返回值为0。此种表达方式仅仅是通知系统,这是一个纯虚函数。n有些类不用来定义对象,而只是作为一个基类去派生新的类,这种类称为抽象类。在抽象类中,可以使用纯虚函数。再次欢迎大家!