《VisualC程序设计教程》第二章C语言基础和面向对.ppt
第2章 C+语言基础和面向对象,2.1 C+语言基础2.2 类2.3 面向对象的编程技术,2.1 C+语言基础,Visual C+的基础是C+语言,利用Visual C+所编译、运行的程序,小到一个界面程序,大到一个大型软件,无一不是用C+语言写出来的。因此,要学好Visual C+,必须对C+语言有深入的了解。,2.1.1 编程基础,1源文件源文件由语句组成。语句用来确定计算机要执行什么操作。例如,下面这一行语句完成了计算半径为10厘米的圆的面积:area=3.14*10*10;每一个语句都要以分号结尾。,2main函数main函数不返回数值,main函数中的第一行将被计算机最先执行到。3数据的输出 当程序中出现cout时,就表示要输出它后面的内容,如果要输出文本内容,可以用双引号把要输出的文本括起来。,4数据的输入使用cin和可实现数据的输入。例如:cina;用户输入数值后,这个数值被存入变量a中。5预处理#include预处理指令告诉编译器装入一个include文件。例如cin和cout被定义在称为iostream.h的文件中(其中.h是头文件的标准扩展名)。,数据类型,C+提供了许多预先定义的数据类型,用户可以把不同的数据类型组合起来构造更复杂的数据类型。1基本数据类型char一一表示字符。如a、b和*都是字符。该类型数据占一个字节的空间。float一一表示浮点数。即带有小数点的数字,例如3.14、-1.50和20.0等等,浮点数有时也称作实数。浮点数的取值范围是3.1410-38到3.41038。该类型数据占四个字节的空间。double一一表示双精度数。双精度数的取值范围是1.710-308到1.710308。该类型数据占八个字节的空间。int表示整数。整数是不包含小数点的数。例如,0,3,30和-59都是整数,但是1.0不是整数。整数的取值范围是-32768到32767。该类型数据占二个字节的空间。,除上述一些常见的数据类型外,还有如下一些数据类型:long一一表示长整型数。取值范围是-2147483648到2147483647。该类型数据占四个字节的空间。Short一一表示短整型数。取值范围是-32768到32767。该类型数据占二个字节的空间。unsigned一一表示无符号整型数。它表示数值总是正的整数。例如unsigned int类型的表示的范围是0到65535。void一一无类型数,用来表明函数不返回值。如:void main()。,数据类型,2聚合数据类型 C+语言还提供了几种聚合数据类型,包括数组、指针、结构、联合、位域和枚举。本书稍后章节将对部分类型做详细介绍。,3类型安全性C+对数据类型有严格的要求,如果把一个变量声明为一种类型,而在实际使用时又试图把它用作另外一种类型,编译器就会产生错误。这种对数据类型的严格要求称作类型安全性。例如:int r;r=“Hello!”;将会出错,因为r是整型,所以不能给它赋一个字符串,因此,应该明确告诉编译器把一种数据类型转换成另一种数据类型,这称作强制类型转换。要做到这一点,只需在被转换的项前面加入要转换的数据类型名。,2.1.3 常量和变量,1常量常量指的是在程序执行过程中不变的数据。它有两种形式,其一是数值形式,如:3.14、135、0.132e+02等;其二是标识符形式,称为符号常量。要使一个标识符成为符号常量,只须在声明前面加上const即可。例如:const int Length=3;Length就是一个符号常量,其值为3。,常量和变量,2变量变量指的是在程序执行过程中其值可以变化的量,任何一个变量必须有确定的名称。只需通过变量的名称,便可以访问存储在变量内的信息。变量名由字母、数字和下划线组成,但有以下一些限制:变量名不能以数字开头;变量名中不能有空格;变量名中除了能使用26个英文字母外,只能使用“_”;变量名不能与C+语言中的关键词同名。表2.1列出了Visual C+的关键词;变量名不能与C+中的库函数名相同。,3变量的作用域,变量的作用域是指变量在程序中的有效使用范围。根据变量的作用域,变量可分为全局变量和局部变量两种类型。全局变量是指在函数外部所定义的变量。两个全局变量不能同名。局部变量是在函数内部定义的变量。在函数开始执行时,局部变量被生成了,并只能在该函数内部使用。当函数结束时,局部变量也随之消失。在函数内,一个名称只能代表一个变量,但是在另一个函数内,这个名称可代表另外一个变量。在函数中所定义形式参数也是局部变量。,C+中的变量作用域的规则:任何在函数内部定义的变量都是这个函数的局部变量。如果在函数中定义了一个变量,则当函数调用时,这个变量也随之生成,可在整个函数内部使用,并且当函数结束时随之消失。函数的所有形参都是这个函数的局部变量。在函数中,若局部变量和全局变量同名,则该函数所使用的是局部变量,而不是同名的全局变量。如果在函数中使用了一个不属于该函数的局部变量,编译程序将寻找同名的全局变量。在一个有某个局部变量的函数中,如果要访问一个与此变量同名的全局变量,则在变量名前加上:(作用域分辨符)。例如,有一个名为area的全局变量,且函数中包含了名为area的局部变量,那么用:area指的是全局变量,而用area指的是局部变量。,2.1.4 运算符,C+语言的运算符是告诉编译程序执行特定算术或逻辑操作的符号,C+语言内部运算符主要有三类:算术运算符、关系与逻辑运算符以及位操作运算符。,1算术运算符 C+算术运算符主要有:+、-、*、/、%、+、-、等,主要用于算术计算。这些运算符的使用相对简单,下面我们重点讲述+运算符。+运算符有两种形式,可以把它放在变量前面(这种增量运算称为前增量),如+a,也可以把它放在变量后面(这种增量运算称为后增量),如a+。+a先把a的值增1,然后再引用a的值,+先引用a的值,然后a的值增加1。-运算符与+运算符类似。,2关系运算符和逻辑运算符关系运算符用于关系运算,比较左右两个表达式的大小或是否相等,其运算结果为逻辑值“真”或“假”。逻辑运算符表示操作数的逻辑关系,其运算结果同样也是逻辑值“真”或“假”。表2.2介绍了在布尔表达式中常用的运算符。,运算符,3位操作运算符位操作是对字节或字中的位(bit)进行测试、置位或移位处理,这里的字节或字是针对char和int类型而言。位操作不能用于float、double、long double、void或其他复杂类型。C+中的位操作符主要包括:&(与)、|(或)、(异或)、(补)、(右移)、(左移)。,4赋值运算符利用赋值运算符=可以给一个变量赋值,例如:area=3.14*10*10;在赋值过程中,赋值号右边的表达式的值被传送到赋值号左边的变量中。可以在一个语句中使用多个赋值符,使多个变量获得相同的值.表2-3所列出的就是常用的复合赋值运算符。,运算符,运算符,5条件运算符 条件运算符是由?和:合成实现的。条件 表达式具有如下形式:expr1?expr2:expr3 它的含义是:如果expr1为真,就返回expr2的值。否则,返回expr3的值。6运算符的运算次序 表2.4列出了运算次序。表中的运算符按优先级从高到低的次序排列(最上方为最高优先级,最下方为最低优先级)。同一行运算符具有相同的优先级。,2.1.5 C+语言的3种程序结构,C+语言的3种程序结构有:顺序结构、选择结构和循环结构。顺序结构是指计算从第一条语句到最后一条语句完全按顺序执行;选择结构是根据用户输入或中间结果去执行若干不同的任务;循环结构是指在程序的某处,需要根据某项条件重复地执行某项任务若干次或直到满足或不满足某条件为止。,1选择结构选择控制语句主要包括ifelse语句和switch、case语句。if语句是在当条件为真时,执行一系列操作;当条件为假时,执行另外一系列操作,if的语法格式:,2.1.5 C+语言的3种程序结构,if(expr)sent1;else sent2;expr代表表达式,例如i1。sent1和sent2代表语句,例如cost=cost+1。expr可以代表任何一个表达式,如果这个表达式为真,就执行sent1,否则,执行sent2。,还可以不要else来构成if语句,其形式是:if(expr)sent;,与if语句不同,switch、case语句专门处理多路分支的情况,其语法格式为:Switch(expr)case va11:sent 1;case val2:sent 2;case valn:sent ndefault:sent n+1;,首先,确定expr的值并且与val1进行比较(val代表某个确定的值,如1或453)。如果expr与val1数值相等,那么就执行sent1和它后面的所有语句。如果expr与val1的数值不相等,那么expr再继续与va12比较,以此类推。如果没有与expr相匹配的值,那么就执行sent n+1。下面的程序段用于输出数字14的英文字符。Switch(n)case 1:coutone;break;case 2:couttwo;break;case 3:coutthree;break;case4:coutfour;break;default:cout”unknown number;注意,在每个case语句中都要使用break。,2.1.5 C+语言的3种程序结构,2循环结构循环结构主要包括for语句、while语句和do while语句。for语句用于反复执行某些语句,其语法格式如下:for(expr1;expr2;expr3)sent;先确定expr1表达式,expr1通常用于初始化循环中用到的变量;然后计算expr2表达式(每次进入循环都必须执行这一步);如果expr2为真,就执行sent,接着就执行expr3;然后再计算expr2表达式;如果expr2为真,就重复上述步骤,直到expr2为假,循环就结束,程序继续执行for循环后面的语句。,如同for语句一样,while循环也是重复多次执行语句,其语法格式是:while(expr)sent;在while循环开始时,先确定expr,如果表达式为真,就执行sent;然后,再确定expr,如果表达式仍为真,就再执行sent。这个过程一直持续到expr为假时为止。,do-while语句的语法格式:do sent;while(expr);do-while构成另一种循环控制,类似于while循环。两者的区别是,使用while循环,表达式在执行while内部语句之前进行判定。因此,使用while有可能不执行任何语句。而do语句是先执行语句,再确定是否符合条件,以决定是否继续。如果条件为真,再次执行语句。否则,循环停止。,函数,1函数的定义和调用2形式参数 函数中定义形参的方法如下:函数类型 函数名(data_type1 arg1,data_type2 arg2,.),3函数返回值函数要得到一个返回值,必须注意以下两点:在声明函数时,函数名前面写上要返回数据的类型,而不要写void。在函数中用return来返回函数的值。return关键词可以起到立刻离开函数并返回一个值的作用。如果在一个函数的中间使用了return,执行return命令后,return后面的程序代码就不被执行。,指针,指针是C+中一类非常重要的数据类型,它可以更好地表示复杂的数据结构,有些其他数据类型无法或很难实现的操作,都可以利用指针来完成。,1指针的定义方法定义一个指针变量格式如下:类型*指针变量名;例如:int*pointer;定义一个整型指针变量pointer。,指针,2指针的地址使用指针之前,必须给它赋值,也就是说,必须把要指向的内存地址填入指针。要把一个变量的地址送入指针变量,方法是:指针变量=&变量;该语句序列生成了一个称为pointer的整型指针,指针内填入了变量number的地址。向一个指针变量赋值的过程中,必须保证指针变量的类型与所获得地址类型的一致性。例如,如果有一个指向一个整数的指针,只能在这个指针内填入整型变量的地址。,3复引用指针复引用指针是指引用指针变量所指向的存储单元,其方法是在指针名称前加一个*。例如程序段:int*pointer;int number=10;pointer=输出结果为10。,指针,4指向结构的指针例如定义了以下结构:Class MyStr Public:int data;float value;MyStr*pointer;,可以用如下形式来访问结构的成员:(*pointer).value;为了方便,也可以用下面所示的形式来表示成员:foo-Value;在C+程序中经常可以看到“指针-成员”的表示法。,5动态分配内存利用new命令可以动态地分配内存,其方法是:指针=new 类型;当使用new生成一个指针时,唯一能够记录这个内存地址位置的就是指针。例如程序代码:int*pointer;pointer=new int;*pointer=15;pointer=new int;在代码的最后一行为pointer分配了新的内存。虽然整数15仍然保留在内存内,但是,由于pointer存储的内容不再是数据15所在的地址,所以无法访问它。如果不再使用为指针变量所分配的内存空间,就应释放这些空间,这个处理过程称为“释放内存”。方法是:delete 指针变量;,指针,6字符串与指针字符串表示一个连续的字符序列。在处理字符串时,用指向字符串第一项的指针可以访问字符串。例如程序段:char*mystring=”Visual C+6.0”;产生了一个内容为”Visual C+6.0”的字符串。变量mystring是指向这个字符串的指针。用程序段:cout mystring;则可以输出字符串。,数组,数组可以生成包含相同类型的若干个变量。数组中的每个元素都有一个标号,称之为下标(index),使用数组的下标可以立即访问到数组中的任意一个数组元素。,1数组的声明和数组元素的使用在生成一个数组之前,需要声明数组中的元素数目。例如:int arr20;生成了一个具有20个数组元素的一维数组。其中第1个元素为arr0,最后一个元素为arr19。访问数组元素时,只需在变量名称后面的方括号内写上数组的下标。例如:int arr20;arr0=20;arr1=3;Coutarr0;Cout3*arr1;输出结果为20和30。,数组,2数组初始化在声明数组时,把元素的值也同时输入,称为数组的初始化。例如:int arr5=9,4,5,6,7;初始化的结果是:arr0=9,arr1=4,arr2=5,arr3=6,arr4=7。也可以任意输入几项的值。例如:int arr5=9,4,5;初始化的结果是:arr0=9,arr1=4,arr2=5,arr3=0,arr4=0。,3字符串数组在程序中也可以生成一个字符串数组并且对它进行初始化。下面程序段生成并初始化了一个字符串数组,然后进行打印显示:char*foo3=hello,”goodbye,how are you”;coutfoo0foo1foo2endl;,4多维数组在定义多维数组时,数组有几维,就用几个。例如,下面的程序代码段生成了一个二维数组,共有12个数组元素:int arr34;访问数组中的元素时,也是有几维就用几个,int arr34所定义的12个数组元素是:arr00,arr01,arr02,arr03,arr10,arr11,arr12,arr13,arr20,arr21,arr22,arr23。,2.2 类的声明和定义,类是一种复杂的数据类型,它是将不同类型的数据和与这些数据相关的操作封装在一起的集合体。这有点像C语言中的结构,惟一不同的就是结构没有定义所说的“数据相关的操作”,“数据相关的操作”就是平常经常看到的“方法”,因此,类具有更高的抽象性,类中的数据具有隐藏性,类还具有封装性。,类的结构(也即类的组成)是用来确定一类对象的行为的,而这些行为是通过类的内部数据结构和相关的操作来确定的。这些行为是通过一种操作接口来描述的(也即平时所看到的类的成员函数),使用者只关心的是接口的功能(也就是只关心类的各个成员函数的功能),对它是如何实现的并不感兴趣。而操作接口又被称为这类对象向其他对象所提供的服务。,2.2 类,“类”就是对具有相同数据和相同操作的一组相似对象的定义,即类是对具有相同特征和行为的一个或多个对象的描述。在面向对象编程中,“类”是一个最重要的概念。,2.2.1 类及其成员变量与函数的声明和定义,1类的定义格式 类的定义格式一般地分为说明部分和实现部分。说明部分将告诉使用者“做什么”,而实现部分是告诉使用者“怎么做”。2类的一般定义格式如下:class public:protected:private:;,2.2.1 类及其成员变量与函数的声明和定义,3定义类时应注意的事项(1)在类体中不允许对所定义的数据成员进行初始化。(2)类中的数据成员的类型可以是任意的,包含整型、浮点型、字符型、数组、指针和引用等,也可以是对象。(3)一般地,在类体内先说明公有成员,它们是用户所关心的,后说明私有成员,它们是用户不感兴趣的。在说明数据成员时,一般按数据成员的类型大小,由小至大说明,这样可提高时空利用率。(4)经常习惯地将类定义的说明部分或者整个定义部分(包含实现部分)放到一个头文件中。,2.2.2 构造函数和析构函数,1构造函数构造函数用于创建一个类实例(对象)时自动完成的工作,如相关数据成员初始化等。构造函数具有以下特征:构造函数的名字与类名相同,否则编译程序将把它当作一般的成员函数来处理。构造函数没有返回值,在声明和定义构造函数时是不能说明它的类型的。构造函数的功能是对对象进行初始化,且一般只对数据成员做初始化。在构造函数中一般不做赋初值以外的的事情。构造函数不能像其他成员函数那样被显式地调用,它在对象创建时被调用。在一个类中可以定义多个构造函数。,2.2.2 构造函数和析构函数,拷贝构造函数是一种特殊的构造函数,其形参为本类的对象引用。拷贝构造函数有一个指向类对象的引用作为形式参数,传统上被声明为“const”。class 类名 public:类名(形参);/构造函数 类名(类名&对象名);/拷贝构造函数.;类名:类名(类名&对象名)/拷贝构造函数的实现 函数体,2.2.2 构造函数和析构函数,2析构函数提供构造函数的一个目的是为了自动获取资源,但是还缺少一种对称的操作,它为生命期即将结束的类对象返还相关的资源或者自动释放资源。析构函数(destructor)就是这样一个特殊的类成员函数,它是构造函数的互补。,2.2.3 友元,类具有封装和信息隐藏的特性。只有类的成员函数才能访问类的私有成员,程序中的其他函数是无法访问私有成员的。非成员函数可以访问类中的公有成员,但是如果将数据成员都定义为公有的,这又破坏了隐藏的特性。另外,应该看到在某些情况下,特别是在对某些成员函数多次调用时,由于参数传递,类型检查和安全性检查等都需要时间开销,而影响程序的运行效率。,为了解决上述问题,提出一种使用友元的方案。友元是一种定义在类外部的普通函数,但它需要在类体内进行说明,为了与该类的成员函数加以区别,在说明时前面加以关键字friend。友元不是成员函数,但是它可以访问类中的私有成员。友元的作用在于提高程序的运行效率,但是,它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类。,2.2.3 友元,1友元函数友元函数的特点是能够访问类中的私有成员的非成员函数。友元函数从语法上看,它与普通函数一样,即在定义上和调用上与普通函数一样。,2.2.3 友元,2友元类友元除了前面讲过的函数以外,友元还可以是类,即一个类可以作另一个类的友元。当一个类作为另一个类的友元时,这就意味着这个类的所有成员函数都是另一个类的友元函数。,2.3 面向对象的编程技术,面向对象技术是目前流行的系统设计开发技术,它包括面向对象分析和面向对象程序设计。面向对象程序设计技术的提出,主要是为了解决传统程序设计方法结构化程序设计所不能解决的代码重用问题。,2.3 面向对象的编程技术,面向对象技术是目前流行的系统设计开发技术,它包括面向对象分析和面向对象程序设计。面向对象程序设计技术的提出,主要是为了解决传统程序设计方法结构化程序设计所不能解决的代码重用问题。,2.3.1 面向对象程序设计,结构化程序设计从系统的功能入手,按照工程的标准和严格的规范将系统分解为若干功能模块,系统是实现模块功能的函数和过程的集合。由于用户的需求和软、硬件技术的不断发展变化,按照功能设计的系统模块必然是易变的和不稳定的,这样开发出来的模块可重用性不高。,面向对象程序设计从所处理的数据入手,以数据为中心而不是以服务(功能)为中心来描述系统。它把编程问题视为一个数据集合,而数据相对于功能而言,具有更强的稳定性。面向对象的编程方法具有抽象、封装、继承和多态4个基本特征。,2.3.1 面向对象程序设计,1.抽象抽象就是对一类对象进行概括,抽出它们共同的性质并加以描述的过程。它忽略主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象包括两个方面:一是过程抽象,二是数据抽象。过程抽象是指任何一个明确定义功能的操作都可被使用者作为单个的实体看待,尽管这个操作实际上可能由一系列更低级的操作来完成。数据抽象定义了数据类型和施加于该类型对象上的操作,并限定了对象的值只能通过使用这些操作修改和查看。,2.3.1 面向对象程序设计,2.继承继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和实例变量,并且派生类可以修改或增加新的方法使之更适合特殊的需要。这也体现了大自然中一般与特殊的关系。继承性很好的解决了软件的可重用性问题。比如说,所有的Windows应用程序都有一个窗口,它们可以看作都是从一个窗口类派生出来的。但是有的应用程序用于文字处理,有的应用程序用于绘图,这是由于派生出了不同的子类,各个子类添加了不同的特性。,2.3.1 面向对象程序设计,3.封装封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面进行。面向对象始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。一旦定义了一个对象的特性,则有必要决定这些特性的可见性,即哪些特性对外部世界是可见的,哪些特性用于表示内部状态。通常,应禁止直接访问一个对象,而应通过操作接口访问对象,这称为信息隐藏。,2.3.1 面向对象程序设计,4.多态性多态性是指允许不同类的对象对同一消息作出响应。例如,同样是加法,把两个时间加在一起和把两个整数加在一起肯定完全不同。多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好地解决了应用程序函数同名的问题。,2.3.2 封装,封装是面向对象的特征之一,是对象和类的主要特征。将一组相互关联的静态属性和动态方法组合在一起,构成一个对象,是封装的主要概念之一。封装的另一层含义是指对象内部的私有属性和方法的对外不可见性。这样不仅可以实现私有成员的信息隐藏,而且可以避免各对象之间私有同名成员的互扰。,2.3.3 继承,1继承的种类2类成员的可访问特性3公有继承和私有继承4继承中的同名成员访问5继承中的构造函数,2.3.3 继承,1继承的种类在C+语言中,实现继承的种类包括:(1)单继承(2)多继承(3)重复继承(4)共享继承单继承是指具有单一直接父类的继承关系。多继承是指具有多个直接父类的继承关系。单继承和多继承示意图如图2-1所示。重复继承和共享继承是多继承的一种变异形态。重复继承是指一个子类根据需要多次继承一个父类,且在子类中保留多个父类副本的继承方式,而共享继承则是通过直接和间接的方式多次继承一个父类,但最终只在子类中保留一个父类副本的继承机制。重复继承和共享继承过程都需要以间接方式实现。图2-1 单继承和多继承示意图,2.3.3 继承,2类成员的可访问特性在继承中,可以通过指定类的属性和方法的可访问特性。如上所述,在一个类中,属性和方法都可以指定为私有、公有或受保护,并以此来决定被子类继承的可能性以及被外界访问的可能性,类成员的可访问特性如图2-2所示。具有私有访问特性的属性和方法不能被继承,也不能被外界所访问。具有公有访问特性的属性和方法不仅可以被继承,而且也可以被外界所访问。具有受保护访问特性的属性和方法只可以被继承,而不能被外界所访问。,2.3.3 继承,3公有继承和私有继承 类的继承方式包括公有继承和私有继承两种。公有继承时,父类的受保护成员被继承为子类的受保护成员,父类的公有成员被继承为子类的公有成员,父类的私有成员不能被继承。私有继承时,父类的受保护成员和公有成员都被继承为子类的私有成员。同样,父类的私有成员不能被继承。,2.3.3 继承,4继承中的同名成员访问在继承关系中,父类的非私有成员可以被子类所继承。同时,子类也可以定义父类的同名成员。如果是属性成员同名,则相应产生一个新属性成员,如果是定义了一个和父类具有相同原型的方法成员,则子类方法对父类的同名方法构成覆盖关系。单继承中的同名成员和多继承中的同名成员具有类似的地方,因此,可以以单继承为例说明其使用方法,如表2-3所示:,2.3.3 继承,则在B类方法中直接使用的属性成员ya表示在子类中重新定义的成员(在子类定义中以粗体表示),而只有使用如:A:ya形式的成员才表示需要使用父类中的ya成员。同样,在使用子类中的za成员和使用父类中的za成员时,也需要采用同样的方法。如果定义B类对象为b,则访问子类中的za成员的方法为:b.za而访问父类中的成员za,则需要采用:b.A:za的形式。,在多继承中,如果父类A1和父类A2中同时存在可继承属性成员x,同时在子类B中再次定义了一个同名成员x,则在定义一个子类对象b之后,访问三个类中的同名成员的方法为:b.x/使用子类中的成员b.A1:x/使用父类A1中的成员b.A2:x/使用父类A2中的成员可见,多继承中的同名成员访问和单继承类似。,2.3.3 继承,5继承中的构造函数1)单继承中的构造函数构造函数是类中的一个特殊的函数。应用构造函数的主要目的是期望在创建对象的同时进行必要的初始化。如下例中的CIRCLE类:class CIRCLEprivate:int x,y;/圆心坐标double r;/半径CIRCLE(int a,int b,double x)/构造函数x=a;y=b;r=x;CIRCLE()/构造函数重载public:void draw();void outcenter();void outrad();,当需要创建一个类的实例时,自动调用构造函数,如:CIRCLE c1,c2(1,1,2.5);其中c1的创建调用了无参的构造函数,而c2的创建自动为三个私有属性成员赋初值。当一个类需要被继承时,子类的构造函数就需要同时传递参数到父类的构造函数,以期在生成子类对象的同时调用父类的构造函数.写明定义方式,如这里就可以说:如A是B的派生类A:A():B(),2)多继承中的构造函数多继承是一种复杂的继承关系,是由多个父类派生子类的过程。,2.3.4 多态和虚函数,多态(polymorphism)是指属于不同类的对象对同一消息做出不同的响应,具体表现在函数调用的“一种接口,多种方法”特性。多态性广义地分为静态多态性和动态多态性。静态多态性是指一个实体同时以不同的形式存在。在C+中,静态多态性表现为函数重载(function overload)和运算符重载(operator overload)。动态多态性具体表现为虚函数和覆盖(override)。,1.函数重载所谓函数重载,是指不同的功能代码的函数可以共用一个函数名。这些被重载的函数虽然函数名相同,但每个函数所使用的参数类型、参数序列或参数个数必须不同。即在C+的任何一个类中,可以具有相同的函数,但这些同名函数的参数一定不能相同。函数的参数类型、参数个数和参数次序称为函数签名或函数特征。当函数同名时,C+编译器通过函数签名来识别和调用不同的函数。,2.运算符重载运算符重载就是用一个运算符完成不同的运算操作。它同函数重载在实质上是一样的,因为一个运算符完成的功能实际上是由一个函数实现的,即运算符重载函数。当编译器遇到重载运算符时,会自动调用运算符的重载函数完成操作。,运算符重载的一般形式如下:operator()其中,“返回值类型”指定的是重载运算符函数的返回值的类型;“operator”是要重载的运算符的名称;“形参列表”给出了重载运算符所需要的参数和数据类型。,3.多态性多态性是面向对象程序设计的重要特征之一。它与前面讲过的封装性和继承性构成了面向对象程序设计的三大特征。这三大特征是相互联系的,其中,封装性是基础,继承性是关键,多态性是补充,而多态性又必须存在于继承的环境中。以上所述的函数重载和运算符重载就是C+中的多态性技术。在C+中又将多态性分为两类:编译时多态即静态多态性和运行时多态即动态多态性。,4.虚函数虚函数是在基类中被冠以关键字virtual的成员函数,它提供了一种接口界面。虚函数可以在一个或多个派生类中被重新定义,但要求在派生类中重新定义时,虚函数的函数原型,包括返回类型、函数名、参数个数、参数类型的顺序等都必须完全相同。,本章结束,