《《C/C程序设计》第10章(C语言基础).ppt》由会员分享,可在线阅读,更多相关《《C/C程序设计》第10章(C语言基础).ppt(61页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、10.1概述概述10.2类和对象类和对象10.3构造函数和析构函数构造函数和析构函数10.4继承与派生继承与派生第10章 C+语言基础10.1 概述概述C+不仅扩充了不仅扩充了C面向过程的功能,而且增加了面向面向过程的功能,而且增加了面向对象的功能,这就使对象的功能,这就使C+成为能适应面向对象程序成为能适应面向对象程序设计的现代大型语言。设计的现代大型语言。C+不是简单地对不是简单地对C做了某做了某些改进,而是在些改进,而是在C成功的基础上进行了一场革命。成功的基础上进行了一场革命。赋予赋予C以新的生命力。以新的生命力。客观世界中任何一个事物都可以看成一个对象。或客观世界中任何一个事物都可以
2、看成一个对象。或者说,客观世界是由千千万万个对象组成的,它们者说,客观世界是由千千万万个对象组成的,它们之间通过一定的渠道相互联系,如图之间通过一定的渠道相互联系,如图10.1示意。在示意。在实际生活中,人们往往在一个对象中进行活动,或实际生活中,人们往往在一个对象中进行活动,或者说对象是进行活动的基本单位。作为对象,它应者说对象是进行活动的基本单位。作为对象,它应该至少有两个要素:一是从事活动的主体;二是活该至少有两个要素:一是从事活动的主体;二是活动的内容。要进行活动,或者是事先安排好一个活动的内容。要进行活动,或者是事先安排好一个活动计划,或者由外界临时通知。动计划,或者由外界临时通知。
3、图图10.1 图图10.2从计算机的角度看,一个对象应该包括两个要素:从计算机的角度看,一个对象应该包括两个要素:一是数据;二是需要进行的操作。对象就是一个包一是数据;二是需要进行的操作。对象就是一个包含数据以及与这些数据有关的操作的集合。图含数据以及与这些数据有关的操作的集合。图10.2 表示一个对象是由数据和操作代码组成的。表示一个对象是由数据和操作代码组成的。传统的面向过程程序设计是围绕功能进行的,用一传统的面向过程程序设计是围绕功能进行的,用一个函数实现一个功能。所有的数据都是公用的,一个函数实现一个功能。所有的数据都是公用的,一个函数可以使用任意一组数据,而一组数据又能被个函数可以使
4、用任意一组数据,而一组数据又能被多个函数所使用(见图多个函数所使用(见图10.3)。程序设计者必须考)。程序设计者必须考虑每一个细节,什么时候对什么数据进行操作。当虑每一个细节,什么时候对什么数据进行操作。当程序规模较大、数据很多、操作种类繁多时,程序程序规模较大、数据很多、操作种类繁多时,程序设计者往往感到难以应付。设计者往往感到难以应付。图图10.3面向对象程序设计采用新的思路。它面对的是一个面向对象程序设计采用新的思路。它面对的是一个个对象。所有的数据分别属于不同的对象。实际上,个对象。所有的数据分别属于不同的对象。实际上,每一组数据都是有特定的用途的,是某种操作的对每一组数据都是有特定
5、的用途的,是某种操作的对象。把相关的数据和操作放在一起,形成一个整体,象。把相关的数据和操作放在一起,形成一个整体,与外界相对分隔。面向对象程序设计方法的一个重与外界相对分隔。面向对象程序设计方法的一个重要特点就是要特点就是“封装性封装性”,把数据和操作代码封装,把数据和操作代码封装在一个对象中。程序设计者的任务包括两个方面:在一个对象中。程序设计者的任务包括两个方面:一是设计对象,即决定把哪些数据和操作封装在一一是设计对象,即决定把哪些数据和操作封装在一起;二是在此基础上怎样通知有关对象完成所需的起;二是在此基础上怎样通知有关对象完成所需的任务。这时他如同一个总调度,不断地向各个对象任务。这
6、时他如同一个总调度,不断地向各个对象发出命令,让这些对象活动起来,完成自己范围内发出命令,让这些对象活动起来,完成自己范围内的操作。各个对象的操作完成了,整体任务也就完的操作。各个对象的操作完成了,整体任务也就完成了。显然,对一个大型任务来说,面向对象程序成了。显然,对一个大型任务来说,面向对象程序设计方法将是十分有效的,它能大大降低程序设计设计方法将是十分有效的,它能大大降低程序设计人员的工作难度,减少出错机会。人员的工作难度,减少出错机会。10.2 类类 和和 对对 象象每一个实体都是对象。有一些对象是具有相同的结每一个实体都是对象。有一些对象是具有相同的结构和特性的。在构和特性的。在C+
7、中对象的类型称为中对象的类型称为“类类”(class)。类代表了某一批对象的共性和特征。类代表了某一批对象的共性和特征。可以说:类是对象的抽象,而对象是类的具体实例。可以说:类是对象的抽象,而对象是类的具体实例。正如同结构体类型和结构体变量的关系一样,人们正如同结构体类型和结构体变量的关系一样,人们先声明一个结构体类型,然后用它去定义结构体变先声明一个结构体类型,然后用它去定义结构体变量。同一个结构体类型可以定义出多个不同的结构量。同一个结构体类型可以定义出多个不同的结构体变量。在体变量。在C+中也是先声明一个中也是先声明一个“类类”类型,然类型,然后用它去定义若干个同类型的对象。对象就是一个
8、后用它去定义若干个同类型的对象。对象就是一个“类类”类型的变量。类是用来定义对象的一种抽象类型的变量。类是用来定义对象的一种抽象数据类型,或者说它是产生对象的模板。它的性质数据类型,或者说它是产生对象的模板。它的性质和其他数据类型(如整型、实型、枚举类型、结构和其他数据类型(如整型、实型、枚举类型、结构体类型)相同。在一开始时弄清对象和类的关系是体类型)相同。在一开始时弄清对象和类的关系是十分重要的。十分重要的。C+对对C的改进,最重要的就是增加了的改进,最重要的就是增加了“类类”这样一这样一种数据类型。所以种数据类型。所以C+开始时被称为开始时被称为“带类的带类的C”。所有面向对象的语言都提
9、供了这种数据类型。所有面向对象的语言都提供了这种数据类型。在在C+中怎样声明一个中怎样声明一个“类类”类型呢?其方法和声类型呢?其方法和声明一个结构体类型是相似的。下面是我们已熟悉的明一个结构体类型是相似的。下面是我们已熟悉的声明一个结构体类型:声明一个结构体类型:struct studentint num;char name10;char sex;struct student student1,student2;上面声明了一个名为上面声明了一个名为student的结构体类型并定义了的结构体类型并定义了两个结构体变量两个结构体变量student1和和student2。可以看到它可以看到它只包括
10、数据(变量),没有包括操作。如果希望对只包括数据(变量),没有包括操作。如果希望对结构体变量中各成员赋值或输出它们的值,需要另结构体变量中各成员赋值或输出它们的值,需要另外编写有关的操作语句。结构体变量中各成员在本外编写有关的操作语句。结构体变量中各成员在本作用域中都是作用域中都是“敞开敞开”的,大家都可以用,而且不的,大家都可以用,而且不受任何限制。这就造成程序的不安全。现在我们声受任何限制。这就造成程序的不安全。现在我们声明一个类:明一个类:class stud/以以class开头开头int num;char name10;char sex;/以上以上3行是数据成员行是数据成员 void
11、display()/这是成员函数这是成员函数 coutnum:numendl;coutname:nameendl;coutsex:sexendl;/以上以上4行是操作代码行是操作代码;stud stud1,stud2;/定义了两个定义了两个stud 类的对象类的对象 这就声明了一个名为这就声明了一个名为stud的类。可以看到声明的类。可以看到声明“类类”的方法是由声明结构体类型的方法发展而来的。它的方法是由声明结构体类型的方法发展而来的。它除了包含数据部分以外,还包括了对这些数据的操除了包含数据部分以外,还包括了对这些数据的操作部分,也就是把数据和操作封装在一起。作部分,也就是把数据和操作封装
12、在一起。display是一个函数,用来输出本对象中学生的学是一个函数,用来输出本对象中学生的学号、姓名和性别。类除了具有封装性外,还采用了号、姓名和性别。类除了具有封装性外,还采用了信息隐蔽原则,使类中的成员与外界的联系减少到信息隐蔽原则,使类中的成员与外界的联系减少到最低限度。现在封装在最低限度。现在封装在stud中的成员都对外界隐蔽,中的成员都对外界隐蔽,外界不能调用它们。只有本类中的函数外界不能调用它们。只有本类中的函数display可可以调用同一类中的数据。以调用同一类中的数据。在本类中没有指定的操作一律不能执行。这当然安在本类中没有指定的操作一律不能执行。这当然安全了,但是谁来通知执
13、行全了,但是谁来通知执行display函数呢?它无法函数呢?它无法启动,缺少对外界的接口。因此,不能把全部成员启动,缺少对外界的接口。因此,不能把全部成员与外界隔离,一般是把数据隐蔽起来,而把成员函与外界隔离,一般是把数据隐蔽起来,而把成员函数作为对外界的接口,譬如可以从外界发出一个命数作为对外界的接口,譬如可以从外界发出一个命令,通知该对象执行令,通知该对象执行display函数,输出某一学生函数,输出某一学生的有关数据。的有关数据。类的成员包括两大类,一类是类的成员包括两大类,一类是“私有的私有的”(private),即外界不能调用;另一类是即外界不能调用;另一类是“公用的公用的”(pub
14、lic),有的书译为有的书译为“公有的公有的”,即公开的,外界可以调,即公开的,外界可以调用(稍后还要介绍一类即用(稍后还要介绍一类即“受保护的受保护的”(protected)。可以将上面类的声明改为可以将上面类的声明改为 class stud private:/声明以下部分为私有的声明以下部分为私有的 int num;char name10;char sex;public:/声明以下部分为公用的声明以下部分为公用的 void display()coutnum:numendl;coutname:nameendl;coutsex:sexendl;/以上以上4行是操作代码行是操作代码;stud s
15、tud1,stud2;/定义了两个定义了两个stud 类的对象类的对象现在声明了现在声明了display函数是公用的,外界就可以调用函数是公用的,外界就可以调用该函数了。该函数了。如果在类的声明中既不指定如果在类的声明中既不指定private,也不指定也不指定public,则系统就认为是私有的(第一次的类声明就属此则系统就认为是私有的(第一次的类声明就属此情况)。情况)。顺便介绍在面向对象程序设计中的几个名词:类中顺便介绍在面向对象程序设计中的几个名词:类中的成员函数称为的成员函数称为“方法方法”,“方法方法”是对数据的是对数据的操作操作。一个。一个“方法方法”对应一种操作。显然,只有被对应一
16、种操作。显然,只有被声明为声明为public的方法(成员函数)才能被对象外界的方法(成员函数)才能被对象外界所激活。外界是通过发所激活。外界是通过发“消息消息”来激活有关方法的。来激活有关方法的。所谓所谓“消息消息”,其实就是一个,其实就是一个命令命令,由程序语句来,由程序语句来实现。例如想输出对象实现。例如想输出对象stud1中的学生学号、姓名、中的学生学号、姓名、性别等信息,可以在程序中写性别等信息,可以在程序中写stud1.display();这就是向对象这就是向对象stud1发出的一个发出的一个“消息消息”,通知它执,通知它执行行display“方法方法”(即(即display函数)。
17、在这里一个函数)。在这里一个语句中涉及到语句中涉及到3个术语:对象、方法和消息。个术语:对象、方法和消息。归纳以上对类型的声明,可以得到其一般形式:归纳以上对类型的声明,可以得到其一般形式:class 类名类名private:私有的数据和成员函数私有的数据和成员函数;public:公用的数据和成员函数公用的数据和成员函数;C+增加了增加了class类型后,仍保留了结构体类型类型后,仍保留了结构体类型(struct)和共用体类型和共用体类型(union),而且把它们的功而且把它们的功能也扩展了,允许在声明的结构体和共用体类型中能也扩展了,允许在声明的结构体和共用体类型中包括成员函数,也就是可以用
18、包括成员函数,也就是可以用struct和和union来声明来声明一个类型。但它们和一个类型。但它们和class声明的类有所区别。声明的类有所区别。用用struct声明的类,如果不作声明的类,如果不作private或或public声明,声明,系统将其成员默认定为系统将其成员默认定为public(公用的),在需要公用的),在需要时可以自己用显式声明重新指定为时可以自己用显式声明重新指定为private或或public。用用union声明的类,如果不作声明的类,如果不作private或或public声明,声明,系统将其成员默认定为系统将其成员默认定为public(公用的),且不能公用的),且不能改变
19、。改变。用用class声明的类,如果不作声明的类,如果不作private或或public声明,系声明,系统将其成员默认定为统将其成员默认定为private(私有的),在需要私有的),在需要时可以自己用显式声明改变。时可以自己用显式声明改变。10.3 构造函数和析构函数构造函数和析构函数10.3.1 构造函数构造函数在建立一个对象时,常常需要作某些初始化的工作在建立一个对象时,常常需要作某些初始化的工作(例如对数据赋予初值),(例如对数据赋予初值),C+提供了一种特殊的提供了一种特殊的成员函数成员函数构造函数构造函数(constructor)。这种函数这种函数与其他成员不同,不需要用户发与其他成
20、员不同,不需要用户发“消息消息”来激活来激活它,而是在建立对象时自动执行。构造函数是由用它,而是在建立对象时自动执行。构造函数是由用户定义的,它必须与类名同名,以便系统能识别它户定义的,它必须与类名同名,以便系统能识别它并把它作为构造函数。现在我们在前面声明的类中并把它作为构造函数。现在我们在前面声明的类中加入构造函数。加入构造函数。class stud private:/声明以下部分为私有的声明以下部分为私有的 int num;char name10;char sex;public:stud()/定义构造函数,函数名与类名相同定义构造函数,函数名与类名相同 num=10010;strcpy(
21、name,Wang-li);sex=F;/以上以上3行为给数据赋初值行为给数据赋初值 void display()/定义成员函数定义成员函数 coutnum:numendl;coutname:nameendl;coutsex:sexendl;stud stud1;/在定义对象在定义对象stud1时自动执行构造函数时自动执行构造函数注意:注意:构造函数不需用户调用,而是在定义一个对象构造函数不需用户调用,而是在定义一个对象时由系统自动执行,而且只能执行一次。构造函数一时由系统自动执行,而且只能执行一次。构造函数一般声明为般声明为public,无返回值,也不需加无返回值,也不需加void类型声明。
22、类型声明。现在写成一个完整的程序。现在写成一个完整的程序。例例10.1 建立一个对象,输出学生的学号、姓名、性别。建立一个对象,输出学生的学号、姓名、性别。#include#includevoid main()class stud /声明一个类声明一个类 private:/私有部分私有部分 int num;char name10;char sex;public:/公用部分公用部分 stud()/定义构造函数,函数名与类名相同定义构造函数,函数名与类名相同 num=10010;/给数据赋初值给数据赋初值 strcpy(name,Wang-li);sex=F;void display()/定义成定
23、义成员函数,输出对象的数据员函数,输出对象的数据 coutnum:numendl;coutname:nameendl;coutsex:sexendl;stud stud1;/在定义对象在定义对象stud1时自动执行构造时自动执行构造函数函数stud1.display();/从对象外面调用从对象外面调用display函数函数可以看到整个程序很简单,它包括三部分:可以看到整个程序很简单,它包括三部分:声明声明一个类;一个类;定义一个对象;定义一个对象;向对象发出消息,向对象发出消息,执行对象中的成员函数执行对象中的成员函数display。在定义在定义stud1对象对象时自动执行了构造函数时自动执行
24、了构造函数stud(),因此对象中的数据因此对象中的数据成员均被赋了值。执行成员均被赋了值。执行display函数输出以下信息:函数输出以下信息:num:10010name:Wang-lisex:F在程序中可以看到只有对象中的函数才能引用本对在程序中可以看到只有对象中的函数才能引用本对象中的数据。如果在对象外面直接用象中的数据。如果在对象外面直接用coutstud1.num;企图输出学生的学号是不行的。由此可体会到类的企图输出学生的学号是不行的。由此可体会到类的特点。特点。如果要建立两个对象,分别对数据赋予初值,就不如果要建立两个对象,分别对数据赋予初值,就不能这样定义构造函数能这样定义构造函
25、数stud了,因为它会使两个学生了,因为它会使两个学生的初值相同,例如姓名都是的初值相同,例如姓名都是Wang-li。应该分别赋应该分别赋予不同的初值。可将构造函数修改如下:予不同的初值。可将构造函数修改如下:stud(int n,char nam,char s)/定义构造函数,有形定义构造函数,有形参参 num=n;strcpy(name,nam);sex=s;此时数据的值不由构造函数此时数据的值不由构造函数stud确定,而是在调用此确定,而是在调用此函数时由实参传来。但应注意构造函数不同于一般函数时由实参传来。但应注意构造函数不同于一般的成员函数,不能这样调用:的成员函数,不能这样调用:s
26、tud1.stud(10010,“Wang-li”,f);/企图用调用一般成企图用调用一般成员函数的方法来调用构造函数员函数的方法来调用构造函数前已说明构造函数是在建立对象时调用的,因此实前已说明构造函数是在建立对象时调用的,因此实参应该在建立对象时给出。如:参应该在建立对象时给出。如:stud stud1(10010,Wang-li,f),stud2(10011,Zhang-fun,m);现在定义了两个对象现在定义了两个对象stud1和和stud2,它们的数据初值它们的数据初值是不同的。如果想分别输出两个学生的数据,可以是不同的。如果想分别输出两个学生的数据,可以用以下的语句:用以下的语句:
27、stud1.display();stud2.display();此时的输出如下:此时的输出如下:num:10010name:Wang-lisex:fnum:10011name:Zhang-funsex:m用户也可以不定义构造函数,编译系统会自动生成用户也可以不定义构造函数,编译系统会自动生成一个构造函数,该函数没有参数,不进行任何操作。一个构造函数,该函数没有参数,不进行任何操作。构造函数也可以重载,下面是两个重载函数:构造函数也可以重载,下面是两个重载函数:stud()/在构造函数中对数据赋初值在构造函数中对数据赋初值 num=10010;strcpy(name,Wang-li);sex=F
28、;stud(int n,char nam,char s)/有形参,由实有形参,由实参将值传给形参参将值传给形参 num=n;strcpy(name,nam);sex=s;在定义对象时允许有实参和无实参。如:在定义对象时允许有实参和无实参。如:stud stud1;/不带实参,数据初值在构造函数中不带实参,数据初值在构造函数中指定指定stud stud2(10011,Zhang-fun,m);/带实参,数据带实参,数据初值由实参给出初值由实参给出10.3.2 析构函数析构函数析构函数析构函数(destructor)与构造函数相反,当对象脱与构造函数相反,当对象脱离其作用域时(例如对象所在的函数已
29、调用完毕),离其作用域时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做系统自动执行析构函数。析构函数往往用来做“清清理善后理善后”的工作(例如在建立对象时用的工作(例如在建立对象时用new开辟了开辟了一片内存空间,应在退出前在析构函数中用一片内存空间,应在退出前在析构函数中用delete释放)。释放)。析构函数名也应与类名相同,只是在函数名前面加析构函数名也应与类名相同,只是在函数名前面加一个波浪符一个波浪符,例如,例如stud(),以区别于构造函数。以区别于构造函数。它不能带任何参数,也没有返回值(包括它不能带任何参数,也没有返回值(包括void类型)类型)。只能
30、有一个析构函数,不能重载。如果用户没有。只能有一个析构函数,不能重载。如果用户没有编写析构函数,编译系统会自动生成一个缺省的析编写析构函数,编译系统会自动生成一个缺省的析构函数,它也不进行任何操作。所以许多简单的类构函数,它也不进行任何操作。所以许多简单的类中没有用显式的析构函数。中没有用显式的析构函数。例例10.2 包含构造函数和析构函数的包含构造函数和析构函数的C+程序。程序。#include#includeclass stud /声明一个类声明一个类 private:/私有部分私有部分 int num;char name10;char sex;public:/公用部分公用部分 stud(
31、int n,char nam,char s)/构造函数构造函数 num=n;strcpy(name,nam);sex=s;stud()/析构函数析构函数 void display()/成员函数,输出对象的数据成员函数,输出对象的数据 coutnum:numendl;coutname:nameendl;coutsex:sexendl;void main()stud stud1(10010,Wang-li,f),stud2(10011,Zhang-fun,m);/建立两个对象建立两个对象 stud1.display();/输出学生输出学生1的数据的数据 stud2.display();/输出学生输
32、出学生2的数据的数据现在把类的声明放在现在把类的声明放在main函数之前,它的作用域是函数之前,它的作用域是全局的。这样做可以使全局的。这样做可以使main函数更简练一些。在函数更简练一些。在main函数中定义了两个对象并且给出了初值。然函数中定义了两个对象并且给出了初值。然后输出两个学生的数据。运行结果和例后输出两个学生的数据。运行结果和例10.1中给出中给出的相同。在本例中,析构函数并无任何实质上的作的相同。在本例中,析构函数并无任何实质上的作用,我们把它写出来,只是为了说明析构函数的使用,我们把它写出来,只是为了说明析构函数的使用方法。用方法。在本程序中,成员函数是在类中定义的,如果成员
33、在本程序中,成员函数是在类中定义的,如果成员函数的数目很多以及函数的长度很长,类的声明就函数的数目很多以及函数的长度很长,类的声明就会占很大的篇幅,不利于阅读程序。可以在类的外会占很大的篇幅,不利于阅读程序。可以在类的外面定义成员函数,而在类中只用函数的原型作声明。面定义成员函数,而在类中只用函数的原型作声明。例例10.3 在类的外面定义成员函数。在类的外面定义成员函数。#include#includeclass stud/声明一个类声明一个类 private:int num;char name10;char sex;public:stud(int n,char nam,char s);/对构
34、造函数的原型对构造函数的原型声明声明 stud();/对析构函数的原型声明对析构函数的原型声明 void display();/对成员函数对成员函数display的原型声明的原型声明;stud stud(int n,char nam,char s)/对构造函数对构造函数的定义的定义 num=n;strcpy(name,nam);sex=s;stud stud()/对析构函数的定义对析构函数的定义 void stud display()/对成员函数对成员函数display的定义的定义 coutnum:numendl;coutname:nameendl;coutsex:sexendl;void m
35、ain()stud stud1(10010,Wang-li,f),stud2(10011,Zhang-fun,m);stud1.display();/输出学生输出学生1的数据的数据 stud2.display();/输出学生输出学生2的数据的数据 请读者注意在类声明的外部定义函数,必须指定类请读者注意在类声明的外部定义函数,必须指定类名。函数首行的形式为名。函数首行的形式为函数类型函数类型 类名类名 函数名(形参表列)函数名(形参表列)不能写成不能写成void display()/未指定类名未指定类名如果这样写,编译系统会把它作为普通的函数处理,如果这样写,编译系统会把它作为普通的函数处理,而
36、不作为类中的成员函数。也不要写成:而不作为类中的成员函数。也不要写成:stud void display()/函数类型位置不函数类型位置不对对stud display()是一个整体,说明是是一个整体,说明是stud类中的类中的display函数。不能把函数。不能把stud 和和display()分隔开来。分隔开来。虽然函数在类的外部定义,但在调用成员函数时会虽然函数在类的外部定义,但在调用成员函数时会根据类中函数的原型声明找到函数的定义(函数代根据类中函数的原型声明找到函数的定义(函数代码),从而执行该函数。码),从而执行该函数。也可以将在类外部定义的函数声明为也可以将在类外部定义的函数声明为
37、“内置函数内置函数”,这样在编译时就将函数代码代入到类中的函数这样在编译时就将函数代码代入到类中的函数调用处,以提高程序执行效率。只需在函数定义的调用处,以提高程序执行效率。只需在函数定义的首行最左端加上首行最左端加上inline即可。如:即可。如:inline void stud display()10.4 继继 承承 与与 派派 生生10.4.1 继承与派生的概念继承与派生的概念面向对象技术强调软件的可重用性。在面向对象技术强调软件的可重用性。在C+中可重中可重用性是通过用性是通过“继承继承”这一机制来实现的。因此,这一机制来实现的。因此,继承是继承是C+的一重要组成部分。的一重要组成部分
38、。前面介绍了类,一个类中包含了若干数据成员和成前面介绍了类,一个类中包含了若干数据成员和成员函数。每一个类的数据成员和成员函数是不相同员函数。每一个类的数据成员和成员函数是不相同的。但有时两个类的内容基本相同或有一部分相同。的。但有时两个类的内容基本相同或有一部分相同。例如前面我们声明了学生基本数据的类例如前面我们声明了学生基本数据的类stud:class studprivate:int num;char name10;char sex;public:void display()/对成员函数对成员函数display的定义的定义 coutnum:numendl;coutname:nameendl
39、;coutsex:sexendl;如果学校的某部门除了需要用到学号、姓名、性别如果学校的某部门除了需要用到学号、姓名、性别以外,还需要用到年龄、地址等信息。当然可以重以外,还需要用到年龄、地址等信息。当然可以重新声明另一个类:新声明另一个类:class stud 1private:int num;/此行原来己有此行原来己有 char name10;/此行原来己有此行原来己有 char sex;/此行原来己有此行原来己有 int age;char addr20;public:void display();/此行原来己有此行原来己有 coutnum:numendl;/此行原来己有此行原来己有 co
40、utname:nameendl;/此行原来己有此行原来己有 coutsex:sexendl;/此行原来己有此行原来己有 coutage:ageendl;coutaddress:addrendl;可以看到有相当一部分是原来已有的。很多人自然可以看到有相当一部分是原来已有的。很多人自然会想到能否利用原有声明的类作为基础,再加上新会想到能否利用原有声明的类作为基础,再加上新的内容即可,以减少重复的工作量。的内容即可,以减少重复的工作量。C+提供的提供的“继承继承”机制就是为了解决这个问题。机制就是为了解决这个问题。举一个日常生活中的例子。如果已经定义了举一个日常生活中的例子。如果已经定义了“马马”的
41、特征,现在需要说明什么是的特征,现在需要说明什么是“公马公马”,只需在,只需在“马马”的特征的基础上增加的特征的基础上增加“雄性雄性”这一特征即可,这一特征即可,不必从头说明什么是马。如果想进一步说明什么是不必从头说明什么是马。如果想进一步说明什么是“白色的公马白色的公马”,只需在只需在“公马公马”的基础上再增的基础上再增加说明加说明“颜色是白的颜色是白的”即可。也就是说:即可。也就是说:“公马公马”继承了继承了“马马”的全部特征,加上的全部特征,加上“雄性雄性”的新特征。的新特征。“白公马白公马”继承了继承了“公马公马”的全部特征,再增加的全部特征,再增加“白色白色”的特征。而的特征。而“公
42、马公马”是是“马马”派生出来派生出来的一个分支,的一个分支,“白公马白公马”是是“公马公马”派生出来的派生出来的一个分支。见图一个分支。见图10.4示意。示意。在在C+中所谓中所谓“继承继承”就是在一个已存在的类的基就是在一个已存在的类的基础上建立一个新的类。已存在的类(好比础上建立一个新的类。已存在的类(好比“马马”)称为称为“基类基类”或或“父类父类”。新建立的类称为。新建立的类称为“派派生类生类”或或“子类子类”。见图见图10.5示意。示意。派生类继承派生类继承了基类的所有数据成员和成员函数,并增加新的成了基类的所有数据成员和成员函数,并增加新的成员。员。图图10.4 图图10.510.
43、4.2 建立派生类的方法建立派生类的方法先通过一个例子说明怎样通过继承来建立派生类。先通过一个例子说明怎样通过继承来建立派生类。例例10.4通过继承来建立派生类。通过继承来建立派生类。假设已经声明了一个基类假设已经声明了一个基类stud(见前面的介绍),在见前面的介绍),在此基础上声明一个派生类此基础上声明一个派生类student:class student:public stud /声明基类是声明基类是stud private:int age;/新增加的数据成员新增加的数据成员 char addr30;/新增加的数据成员新增加的数据成员 public:void display-1()/新增加
44、的成员函数新增加的成员函数 coutage:ageendl;coutaddress:addrendl;仔细观察第一行仔细观察第一行:class student:public stud 在在class后面的后面的student是新建的类名。冒号后面的是新建的类名。冒号后面的stud表示是已存在的基类。在表示是已存在的基类。在stud之前有一关键字之前有一关键字public,用来表示基类用来表示基类stud中的成员在派生类中的成员在派生类student中的使用权限。基类名前面有中的使用权限。基类名前面有public的称为的称为“公用派生类公用派生类”。其含义将在稍后讨论。其含义将在稍后讨论。请仔细
45、阅读以上声明的派生类请仔细阅读以上声明的派生类student和上一节中给和上一节中给出的基类出的基类stud,并将它们放在一起进行分析。并将它们放在一起进行分析。定义派生类的一般形式为定义派生类的一般形式为class 派生类名派生类名:引用权限引用权限 基类名基类名 派生类新增加的数据成员派生类新增加的数据成员 派生类新增加的成员函数派生类新增加的成员函数;“引用权限引用权限”可以是可以是private和和public。默认为默认为private。派生类包括基类成员和自己增加的成员,派生类的派生类包括基类成员和自己增加的成员,派生类的成员函数在引用派生类自己的数据成员时,按前面成员函数在引用派
46、生类自己的数据成员时,按前面介绍过的规则处理(即私有数据成员只能被同一类介绍过的规则处理(即私有数据成员只能被同一类中的成员函数引用,公用成员可以被外界引用)。中的成员函数引用,公用成员可以被外界引用)。而对从基类继承来的成员的引用并不是简单地把基而对从基类继承来的成员的引用并不是简单地把基类的私有成员和公用成员直接作为派生类的私有成类的私有成员和公用成员直接作为派生类的私有成员和公用成员,而要根据基类成员的引用权限和派员和公用成员,而要根据基类成员的引用权限和派生类声明的引用权限共同决定。下面将分别介绍。生类声明的引用权限共同决定。下面将分别介绍。10.4.3 公用派生类公用派生类在声明一个
47、派生类时将基类的引用权限指定为在声明一个派生类时将基类的引用权限指定为public的,该类称为基类的公用派生类。的,该类称为基类的公用派生类。在公用派生类中,基类的公用成员和保护在公用派生类中,基类的公用成员和保护(protected)成员仍然成为派生类中的公用成员和成员仍然成为派生类中的公用成员和保护成员保护成员(关于保护成员将在关于保护成员将在10.4.5节介绍节介绍),而基,而基类的私有成员不能被派生类引用,即成为派生类类的私有成员不能被派生类引用,即成为派生类“不可访问的成员不可访问的成员”,只有基类的成员函数可以引用,只有基类的成员函数可以引用它。基类的成员在公用派生类中的引用权限见
48、表它。基类的成员在公用派生类中的引用权限见表10.1。表表10.1 公用派生类的继承关系公用派生类的继承关系基类私有成员公用成员公用派生类不可访问的成员公用成员例例10.5 访问基类成员。访问基类成员。class stud /声明基类声明基类private:/基类私有成员基类私有成员 int num;char name10;char sex;public:/基类公用成员基类公用成员 void display()coutnum:numendl;coutname:nameendl;coutsex:sexendl;class student:public stud /声明一个公用派生类声明一个公用派
49、生类 private:int age;char addr30;public:void show()coutnum:numendl;/企图引用基类的私有成员,企图引用基类的私有成员,错误。错误。coutname:nameendl;/企图引用基类的私有企图引用基类的私有成员,错误。成员,错误。coutsex:sexendl;/企图引用基类的私有成企图引用基类的私有成员,错误。员,错误。coutage:ageendl;/引用派生类的私有成员,引用派生类的私有成员,正确。正确。coutaddress:addrendl;/引用派生类的私有引用派生类的私有成员,正确。成员,正确。;由于基类的私有成员对派生
50、类来说是不可访问的,因此由于基类的私有成员对派生类来说是不可访问的,因此在派生类中的在派生类中的show函数中直接引用基类的私有数据成函数中直接引用基类的私有数据成员员num,name和和sex是不允许的。可以通过基类的公是不允许的。可以通过基类的公用成员函数来引用基类的私有数据成员。上面对派生用成员函数来引用基类的私有数据成员。上面对派生类类student的声明可改为的声明可改为class student:public stud/声明一个公用派生类声明一个公用派生类 private:int age;char addr20;public:void show()display();/引用基类的公