第8章 继承与派生
8-1. 教学目的与要求
1.理解继承的概念;
2.掌握继承的实现方法;
3.继承中常见问题的处理方法。
8-2. 主要内容及重点:
类是C++中进行数据封装的逻辑单位。继承是面向对象程序设计的一个重要特征之一,它允许在既有类的基础上创建新的类,新类可以从一个或多个既有类中继承操作和数据,而且可以重新定义或加进新的数据和操作,从而形成类的层次或等级。既有类称为基类或父类,在它基础上建立的新类称为派生类、导出类或子类。
本章的重点是派生类的定义和使用、创建派生类对象时构造函数的调用顺序、多重继承中的冲突及其消除方法以及作用域运算符的几种使用方法等。
本章的难点是基类的初始化、多重继承中的冲突以及虚基类等。
8-3. 第8章 继承-课件
3-4. 8-4. 第8章 继承-复习总结 继承是面向对象程序设计方法的基本特性之一,继承可以提高软件的重要性。
本章主要介绍了C++中的继承性的实现方法以及在继承性常见问题的处理方法。包括基类的初始化、访问类型的调整、冲突及其消除方法、成员覆盖、赋值兼容性以及虚基类等。
类的派生包括三种类型:私有派生、保护派生、公有派生。利用构造函数的初始化成员列表,可以在派生类中对基类成员进行初始化。在继承层次关系中要避免冲突的产生,通常是采用指定作用域和定义虚基类这两种方法来解决问题。
8-5. 第8章 继承-练习
8-5-1.思考题:
1
1).派生类有几种方式,每种方式中派生类对基类成员的继承如何?
2). 在创建派生类对象时,构造函数的执行次序是怎样的?析构函数的执行次序是怎样的?
3). 派生类对象如何对基类中的成员进行初始化?
4). 在多重继承中,在什么情况下会产生冲突?如何消除冲突? 5). 列举我们已学习的作用域运算符“::”的所有用途。 6). 属于不同类的对象在什么情况下可以互相赋值? 7).什么叫虚基类?为什么要引进虚基类?
8-5-2.练习题:
课后练习题见练习单元。
第8章 继承与派生
类是C++中进行数据封装的逻辑单位。继承是面向对象程序设计的一个重要特征之一,它允许在既有类的基础上创建新的类,新类可以从一个或多个既有类中继承操作和数据,而且可以重新定义或加进新的数据和操作,从而形成类的层次或等级。既有类称为基类或父类,在它基础上建立的新类称为派生类、导出类或子类。
8.1 继承与派生的基本概念
交通工具
汽车 小汽车 卡车 工具车 轿车 面包车
2
游行车
8.1.1单继承和多继承:
单继承:一个类继承一个一般类特性的继承称为单继承。 多继承:一个类可以继承多个一般类的特性,然后再在继承来的这些一般类的基础上增加自己的特殊性,这种继承方式称为多继承。
如:一个助教博士,他既是一个学生,又是一个老师,如果从学生类和老师类两个一般类继承特性,则助教博士类可以获得这两个类的特性,因而能进一步增强开发效率。
baseClass A baseClass B baseClass
derived C derived A derived B
多继承 单继承
单继承是所有面向对象程序设计语言都具有的功能,但并不是所有的语言都支持多继承,这是由多继承实现的复杂性决定的。C++语言支持多继承。
8.1.2基类和派生类:
在定义类B时,如果它使用了一个已定义的类A的部分或全部成员,则称类B继承了A,或由类A派生出类B。并称类A为基类或父类,类B为派生类或子类。
一个派生类又可以作为另一个类的基类,这样一个基类可以直接或间接派生出若干个派生类,构成树状的继承关系。
但是注意:继承关系不可循环。如:A继承B,B继承,C又继承A,这是非法的。
例类Y继承类X的特性,类Z又继承类Y的特性,从而间接继承来类X的特性。因而类X是类Y的直接基类,是类Z的间接基类,类Y是类X的直接派生类,类Z是类X的间接派生类。类X、Y、Z形成了一个类层次。
如前图.
8.1.3 两个类之间要具有继承关系,它们通常满足:
1)有共同的属性或操作。 2)有细微的差别。
8. 2 派生类说明及其构造函数和析构函数
8.2.1 派生类的说明
从一个基类派生出子类的一般格式为;
class <派生类名>:<基类名> {
3
? //类体,派生类新增的数据成员和成员函数 } ; 其中:
1) class 是类定义的关键字,用于告诉编译器下面定义的是一个类。 2)派生类名是新定义的类名。
3)访问属性是访问说明符,可以是private、public、protected之一。此项的默认值为private,派生类名和访问属性之间用冒号隔开。派生类的访问控制由访问属性来确定,它按下述方式来继承基类的访问属性。 ①.公有派生
如果访问属性是为public,则基类的public成员是派生类的public成员;基类的protected成员是派生类的protected成员;基类的private成员是派生类的private成员;即基类的private成员对派生类仍保持private属性。
显然,派生类中通过公有派生得到的成员还可以被它的子类继承。 ②.私有派生
如果访问属性为private,则基类的public和protected成员都是派生类的private成员;这些私有成员能够被派生类的成员函数直接访问;但在派生类之外不可以被直接访问。但基类的private成员对派生类仍然保持private属性,即不能被派生类成员函数访问。总之当访问属性为private时,派生类的对象不能访问基类中以任何方式定义的成员函数。
显然通过私有派生得到的派生类再派生子类时,其继承得到的基类成员不能被它的子类所继承。 ③.保护派生
如果访问属性为protected,则基类的public和protected成员均是派生类的protected成员;基类的private成员对派生类仍保持private属性。具体来说,基类中声明为protected的数据只能被基类的成员函数或其派生类的成员函数访问;不能被派生类以外的成员函数访问。
对保护派生,基类中的公有成员和保护成员在派生类中均变为保护成员,它们仍然可被它的子类所继承。
4)值得注意的是,C++规定派生类只能访问基类中的公有成员和保护成员,而不能访问类中的私有成员。即
无论哪种派生方式,基类中的私有成员既不允许外部函数访问,也不允许派生类中的成员函数访问,但是可以通过基类提供的公有成员函数访问。
5)公有派生与私有派生的不同点在于基类中的公有成员在派生类中的访问属性。 ●公有派生时,基类中的所有公有成员在派生类中也都是公有的。 ●私有派生时,基类中的所有公有成员只能成为派生类中的私有成员。
6)基类名可以有一个,也可以有多个。如果只有一个基类,则这中继承方式叫做简单继承,也叫单继承;如果基类名有多个,则这种继承方式称为多重继承。各个基类名之间用逗号隔开。
7) 在派生类中声明的名字支配基类中声明的同名的名字,即如果在派生类的成员函数中直接使用该名字的话,则表示使用派生类中声明的名字。 8)在C++中下列成员不能继承:
构造函数和析构函数、友元关系、重载的new和delete运算符。
8.2.2 多重继承
4
由多个基类派生出一个子类的一般格式为: class <类名>:<类名1>,<类名2> - - - <类名n> {
--- //类体,派生类新增的数据成员和成员函数 } ;
冒号后面的部分称基类表,各基类之间用逗号分隔,派生方式规定了派生类从基类中按什么方式继承,缺省的派生方式是private。
任一基类在派生类中只能被继承一次。 例:
class z :public x ,y { //类z公有继承了类x ,私有继承了类y //... } ;
class z :: x , public y { //类z私有继承了类x ,公有继承了类y //... };
class z::public x ,public y { //类z公有继承了类x和类y //... };
8.2.3 派生类的构造函数和析构函数 即基类的初始化
由于派生类继承了基类的一些成员,在创建派生类对象时,对派生类中的数据成员和基类中的数据成员都必须进行初始化,从基类中继承的数据成员可以直接使用基类的构造函数来完成初始化,而新增加的数据成员的初始化要由自己的构造函数来完成。在撤消派生类对象时,也要通过基类的析构函数对派生类中继承得到的数据处理。
1.C++规定,在创建派生类对象时,首先调用基类构造函数,然后再调用派生类构造函数。当撤消派生类对象时,析构函数的调用次序与构造函数的调用次序相反。 2.初始化基类成员通常通过派生类的构造函数实现,一般格式为: <派生类名>::<派生类构造函数名>():<基类名1>(),--- ,<基类名n>() {
- - - 派生类的构造函数 }
其中:
1)是派生类构造函数的形参表,它可以由任意类型的变量组成。
2)冒号后列举的部分为初始化成员列表,在初始化成员列表中,一个基类名只能出现
一次。
3)当初始化成员列表中某一个基类的构造函数的实参表为空时,可以将该构造函数
从初始化列表中删除。
4)、- - - 、分别为调用相应基类构造函数的实参表,其必须与相应构造函数的形参表一致。实参表中的参数可以为任意合法的表达式,该表达式中可以包含中的参数。
5