第11章.ppt
《第11章.ppt》由会员分享,可在线阅读,更多相关《第11章.ppt(121页珍藏版)》请在三一文库上搜索。
1、第11章 继承与派生 第12章 多态性与虚函数 第13章 输入输出流 第14章 C+工具,第4篇 面向对象的程序设计,第11章 继承与派生,11.1 继承与派生的概念 11.2 派生类的声明方式 11.3 派生类的构成 11.4 派生类成员的访问属性 11.5 派生类的构造函数和析构函数 11.6 多重继承 11.7 基类与派生类的转换 11.8 继承与组合 11.9 继承在软件开发中的重要意义,面向对象程序设计有4个主要特点: 抽象、封装、继承和多态性。 要较好地进行面向对象程序设计,还必须了解面向对象程序设计另外两个重要特征继承性和多态性。在本章中主要介绍有关继承的知识,在第12章中将介绍
2、多态性。 面向对象技术强调软件的可重用性(software reusability) 。C+语言提供了类的继承机制,解决了软件重用问题。,在C+中可重用性是通过继承(inheritance)这一机制来实现的。继承是C+的一个重要组成部分。 一个类中包含了若干数据成员和成员函数。在不同的类中,数据成员和成员函数是不相同的。但有时两个类的内容基本相同或有一部分相同。 利用原来声明的类Student作为基础,再加上新的内容即可,以减少重复的工作量。 C+提供的继承机制就是为了解决这个问题。 在第8章已举了马的例子来说明继承的概念。见图11.1示意。,11.1 继承与派生的概念,在C+中,所谓“继承”
3、就是在一个已存在的类的基础上建立一个新的类。已存在的类(例如“马”)称为“基类(base class)”或“父类(father class)”。新建立的类(例如“公马”)称为“派生类(derived class)”或“子类(son class)”。见图11.2示意。 图11.1 图11.2,一个新类从已有的类那里获得其已有特性,这种现象称为类的继承。通过继承,一个新建子类从已有的父类那里获得父类的特性。从另一角度说,从已有的类(父类)产生一个新的子类,称为类的派生。类的继承是用已有的类来建立专用类的编程技术。派生类继承了基类的所有数据成员和成员函数,并可以对成员作必要的增加或调整。一个基类可以
4、派生出多个派生类,每一个派生类又可以作为基类再派生出新的派生类,因此基类和派生类是相对而言的。 以上介绍的是最简单的情况: 一个派生类只从一个基类派生,这称为单继承(single inheritance),这种继承关系所形成的层次是一个树形结构,可以用图11.3表示。,图11.3 请注意图中箭头的方向,在本书中约定,箭头表示继承的方向,从派生类指向基类。,一个派生类不仅可以从一个基类派生,也可以从多个基类派生。一个派生类有两个或多个基类的称为多重继承(multiple inheritance),这种继承关系所形成的结构如图11.4所示。 图11.4,关于基类和派生类的关系,可以表述为: 派生类
5、是基类的具体化,而基类则是派生类的抽象。 图11.5,假设已经声明了一个基类Student,在此基础上通过单继承建立一个派生类Student1: class Student1: public Student/声明基类是Student public: void display_1( ) /新增加的成员函数 coutage: ageendl; coutaddress: addrendl; private: int age; /新增加的数据成员 string addr; /新增加的数据成员 ;,11.2 派生类的声明方式,基类名前面有public的称为“公用继承(public inheritance
6、)”。 声明派生类的一般形式为 class 派生类名: 继承方式 基类名 派生类新增加的成员 ; 继承方式包括: public(公用的),private(私有的)和protected(受保护的),此项是可选的,如果不写此项,则默认为private(私有的)。,派生类中的成员包括从基类继承过来的成员和自己增加的成员两大部分。在基类中包括数据成员和成员函数(或称数据与方法)两部分,派生类分为两大部分: 一部分是从基类继承来的成员,另一部分是在声明派生类时增加的部分。每一部分均分别包括数据成员和成员函数。,11.3 派生类的构成,图11.6,实际上,并不是把基类的成员和派生类自己增加的成员简单地加在
7、一起就成为派生类。构造一个派生类包括以下3部分工作: (1) 从基类接收成员。派生类把基类全部的成员(不包括构造函数和析构函数)接收过来,也就是说是没有选择的,不能选择接收其中一部分成员,而舍弃另一部分成员。 要求我们根据派生类的需要慎重选择基类,使冗余量最小。事实上,有些类是专门作为基类而设计的,在设计时充分考虑到派生类的要求。 (2) 调整从基类接收的成员。接收基类成员是程序人员不能选择的,但是程序人员可以对这些成员作某些调整。,(3) 在声明派生类时增加的成员。这部分内容是很重要的,它体现了派生类对基类功能的扩展。要根据需要仔细考虑应当增加哪些成员,精心设计。 此外,在声明派生类时,一般
8、还应当自己定义派生类的构造函数和析构函数,因为构造函数和析构函数是不能从基类继承的。 派生类是基类定义的延续。可以先声明一个基类,在此基类中只提供某些最基本的功能,而另外有些功能并未实现,然后在声明派生类时加入某些具体的功能,形成适用于某一特定应用的派生类。通过对基类声明的延续,将一个抽象的基类转化成具体的派生类。因此,派生类是抽象基类的具体实现。,既然派生类中包含基类成员和派生类自己增加的成员,就产生了这两部分成员的关系和访问属性的问题。在建立派生类的时候,并不是简单地把基类的私有成员直接作为派生类的私有成员,把基类的公用成员直接作为派生类的公用成员。实际上,对基类成员和派生类自己增加的成员
9、是按不同的原则处理的。,11.4 派生类成员的访问属性,具体说,在讨论访问属性时,要考虑以下几种情况: (1) 基类的成员函数访问基类成员。 (2) 派生类的成员函数访问派生类自己增加的成员。 (3) 基类的成员函数访问派生类的成员。 (4) 派生类的成员函数访问基类的成员。 (5) 在派生类外访问派生类的成员。 (6) 在派生类外访问基类的成员。 对于第(1)和第(2)种情况,比较简单,按第8章介绍过的规则处理,即: 基类的成员函数可以访问基类成员,派生类的成员函数可以访问派生类成员。私有数据成员只能被同一类中的成员函数访问,公用成员可以被外界访问。,第(3)种情况也比较明确,基类的成员函数
10、只能访问基类的成员,而不能访问派生类的成员。第(5)种情况也比较明确,在派生类外可以访问派生类的公用成员,而不能访问派生类的私有成员。 对于第(4)和第(6)种情况,就稍微复杂一些,也容易混淆。 这些牵涉到如何确定基类的成员在派生类中的访问属性的问题,不仅要考虑对基类成员所声明的访问属性,还要考虑派生类所声明的对基类的继承方式,根据这两个因素共同决定基类成员在派生类中的访问属性。,前面已提到: 在派生类中,对基类的继承方式可以有public(公用的),private(私有的)和protected(保护的)3种。不同的继承方式决定了基类成员在派生类中的访问属性。 简单地说: (1) 公用继承(p
11、ublic inheritance) 基类的公用成员和保护成员在派生类中保持原有访问属性,其私有成员仍为基类私有。 (2) 私有继承(private inheritance) 基类的公用成员和保护成员在派生类中成了私有成员。其私有成员仍为基类私有。,(3) 受保护的继承(protected inheritance) 基类的公用成员和保护成员在派生类中成了保护成员,其私有成员仍为基类私有。 保护成员的意思是: 不能被外界引用,但可以被派生类的成员引用,具体的用法将在稍后介绍。,在定义一个派生类时将基类的继承方式指定为public的,称为公用继承,用公用继承方式建立的派生类称为公用派生类(publ
12、ic derived class),其基类称为公用基类(public base class)。 采用公用继承方式时,基类的公用成员和保护成员在派生类中仍然保持其公用成员和保护成员的属性,而基类的私有成员在派生类中并没有成为派生类的私有成员,它仍然是基类的私有成员,只有基类的成员函数可以引用它,而不能被派生类的成员函数引用,因此就成为派生类中的不可访问的成员。 公用基类的成员在派生类中的访问属性见书中表11.1。,11.4.1 公用继承,例11.1 访问公有基类的成员。 下面写出类的声明部分: Class Student/声明基类 public: /基类公用成员 void get_value(
13、) cinnumnamesex; void display( ) cout num: numendl; cout name: nameendl; cout sex: sexendl; private : /基类私有成员 int num; string name; char sex; ; class Student1: public Student /以public方式声明派生类Student1,public: void display_1( ) cout num: numendl; /企图引用基类的私有成员,错误 cout name: nameendl; /企图引用基类的私有成员,错误 cou
14、t sex: sexendl; /企图引用基类的私有成员,错误 cout age: ageendl; /引用派生类的私有成员,正确 cout address: addrendl; /引用派生类的私有成员,正确 private: int age; string addr; ; 由于基类的私有成员对派生类来说是不可访问的,因此在派生类中的display_1函数中直接引用基类的私有数据成员num,name和sex是不允许的。只能通过基类的公用成员函数来引用基类的私有数据成员。,可以将派生类Student1的声明改为 class Student1: public Student/以public方式声明
15、派生类Student1 public: void display_1( ) cout age: ageendl; /引用派生类的私有成员,正确 cout address: addrendl; /引用派生类的私有成员,正确 private: int age; string addr; ; 然后在main函数中分别调用基类的display函数和派生类中的display_1函数,先后输出5个数据。 可以这样写main函数(假设对象stud中已有数据): int main( ) Student1 stud;/定义派生类Student1的对象stud, stud.display( ); /调用基类的公用
16、成员函数,输出基类中3个数据成员的值 stud.display_1(); /调用派生类的公用成员函数,输出派生类中两个数据成员的值 return 0; 请根据上面的分析,写出完整的程序,程序中应包括输入数据的函数。 实际上,程序还可以改进,在派生类的display_1函数中调用基类的display函数,在主函数中只要写一行: stud.display_1(); 即可输出5个数据。,在声明一个派生类时将基类的继承方式指定为private的,称为私有继承,用私有继承方式建立的派生类称为私有派生类(private derived class) ,其基类称为私有基类(private base clas
17、s)。 私有基类的公用成员和保护成员在派生类中的访问属性相当于派生类中的私有成员,即派生类的成员函数能访问它们,而在派生类外不能访问它们。私有基类的私有成员在派生类中成为不可访问的成员,只有基类的成员函数可以引用它们。一个基类成员在基类中的访问属性和在派生类中的访问属性可能是不同的。私有基类的成员在私有派生类中的访问属性见书中表11.2。,11.4.2 私有继承,图11.7 图11.7表示了各成员在派生类中的访问属性。,对表11.2的规定不必死记,只需理解: 既然声明为私有继承,就表示将原来能被外界引用的成员隐藏起来,不让外界引用,因此私有基类的公用成员和保护成员理所当然地成为派生类中的私有成
18、员。私有基类的私有成员按规定只能被基类的成员函数引用,在基类外当然不能访问他们,因此它们在派生类中是隐蔽的,不可访问的。 对于不需要再往下继承的类的功能可以用私有继承方式把它隐蔽起来,这样,下一层的派生类无法访问它的任何成员。 可以知道: 一个成员在不同的派生层次中的访问属性可能是不同的。它与继承方式有关。,例11.2 将例11.1中的公用继承方式改为用私有继承方式(基类Student不改)。 可以写出私有派生类如下: class Student1: private Student/用私有继承方式声明派生类Student1 public: void display_1( ) /输出两个数据成员
19、的值 coutage: ageendl; /引用派生类的私有成员,正确 coutaddress: addrendl; /引用派生类的私有成员,正确 private: int age; string addr; ;请分析下面的主函数:int main( ) Student1 stud1;/定义一个Student1类的对象stud1 stud1.display(); /错误,私有基类的公用成员函数在派生类中是私有函数 stud1.display_1( ); /正确。Display_1函数是Student1类的公用函数 stud1.age=18; /错误。外界不能引用派生类的私有成员 return
20、0; ,可以看到: (1) 不能通过派生类对象(如stud1)引用从私有基类继承过来的任何成员(如stud1.display()或stud1.num)。 (2) 派生类的成员函数不能访问私有基类的私有成员,但可以访问私有基类的公用成员(如stud1.display_1函数可以调用基类的公用成员函数display,但不能引用基类的私有成员num)。 有没有办法调用私有基类的公用成员函数,从而引用私有基类的私有成员呢?有。应当注意到: 虽然在派生类外不能通过派生类对象调用私有基类的公用成员函数,但可以通过派生类的成员函数调用私有基类的公用成员函数(此时它是派生类中的私有成员函数,可以被派生类的任何
21、成员函数调用)。,可将上面的私有派生类的成员函数定义改写为 void display_1( )/输出5个数据成员的值 display(): /调用基类的公用成员函数,输出3个数据成员的值 coutage: ageendl; /输出派生类的私有数据成员 coutaddress: addrendl; /输出派生类的私有数据成员 main函数可改写为 int main( ) Student1 stud1; stud1.display_1( );/display_1函数是派生类Student1类的公用函数 return 0; 这样就能正确地引用私有基类的私有成员。可以看到,本例采用的方法是: 在mai
22、n函数中调用派生类中的公用成员函数stud1.display_1;, 通过该公用成员函数调用基类的公用成员函数display(它在派生类中是私有函数,可以被派生类中的任何成员函数调用); 通过基类的公用成员函数display引用基类中的数据成员。 请根据上面的要求,补充和完善上面的程序,使之成为完整、正确的程序。程序中应包括输入数据的函数。 由于私有派生类限制太多,使用不方便,一般不常使用。,由protected声明的成员称为“受保护的成员”,或简称“保护成员”。从类的用户角度来看,保护成员等价于私有成员。但有一点与私有成员不同,保护成员可以被派生类的成员函数引用。见图11.8示意。 图11.
23、8,11.4.3 保护成员和保护继承,如果基类声明了私有成员,那么任何派生类都是不能访问它们的,若希望在派生类中能访问它们,应当把它们声明为保护成员。如果在一个类中声明了保护成员,就意味着该类可能要用作基类,在它的派生类中会访问这些成员。 在定义一个派生类时将基类的继承方式指定为protected的,称为保护继承,用保护继承方式建立的派生类称为保护派生类(protected derived class),其基类称为受保护的基类(protected base class),简称保护基类。 保护继承的特点是: 保护基类的公用成员和保护成员在派生类中都成了保护成员,其私有成员仍为基类私有。也就是把基
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 11
链接地址:https://www.31doc.com/p-2547042.html