1、C+程序设计第第4 4章章 继承与组合继承与组合1234继承与派生的概念继承与派生的概念第第4章章 继承与组合继承与组合本章学习要点本章学习要点派生类的构成派生类的构成派生类的声明方式派生类的声明方式派生类中基类成员的访问属性派生类中基类成员的访问属性5678派生类的构造函数和析构函数派生类的构造函数和析构函数第第4章章 继承与组合继承与组合本章学习要点本章学习要点基类与派生类对象的关系基类与派生类对象的关系多重继承多重继承组合组合对象组成对象对象组成对象本章学习目标本章学习目标1.理解继承和派生的概念;2.掌握派生类的声明方式,派生类的构成,派生类 对基类的3种继承方式;3.掌握派生类的构造
2、函数和析构函数的执行时机;4.掌握多重继承的声明方法;多重继承派生类的 构造函数与析构函数的定义及执行;5.理解虚基类的概念,掌握其作用和声明方法;6.理解组合的概念,掌握继承与组合在软件开发中 的意义。第第4章章 继承与组合继承与组合v面向对象技术强调软件的可重用性面向对象技术强调软件的可重用性(software reusability)。C+语言提供了语言提供了类的继承机制,解决了软件重用问题。类的继承机制,解决了软件重用问题。第第4章章 继承与组合继承与组合v在在C+中,所谓中,所谓“继承继承”就是在一个或多就是在一个或多个已存在的类的基础上建立一个新的类。个已存在的类的基础上建立一个新
3、的类。已存在的类称为已存在的类称为“基类基类”、“父类父类”或或“一般类一般类”。新建立的类称为。新建立的类称为“派生类派生类”、“子类子类”或或“特殊类特殊类”。4.1 继承与派生的概念继承与派生的概念第第4章章 继承与组合继承与组合v一个新类从已有的类那里获得其已有特性,这种一个新类从已有的类那里获得其已有特性,这种现象称为现象称为类的继承类的继承。通过继承,一个新建子类从。通过继承,一个新建子类从已有的父类那里获得父类的特性。已有的父类那里获得父类的特性。v从另一角度说,从已有的父类产生一个新的子类,从另一角度说,从已有的父类产生一个新的子类,称为称为类的派生类的派生。类的继承是用已有的
4、类来建立专。类的继承是用已有的类来建立专用类的编程技术。用类的编程技术。4.1 继承与派生的概念继承与派生的概念第第4章章 继承与组合继承与组合v派生类派生类继承继承了基类的所有数据成员和成员函数(不了基类的所有数据成员和成员函数(不包括基类的构造函数和析构函数),并可以包括基类的构造函数和析构函数),并可以增加增加自自己的新成员,同时也可以己的新成员,同时也可以调整调整来自基类的数据成员来自基类的数据成员和成员函数。和成员函数。v基类和派生类是相对而言的。基类和派生类是相对而言的。一个基类可以派生出一个基类可以派生出多个派生类,每一个派生类又可以作为基类再派生多个派生类,每一个派生类又可以作
5、为基类再派生出新的派生类。一代一代地派生下去,就形成了类出新的派生类。一代一代地派生下去,就形成了类的继承层次结构,的继承层次结构,4.1 继承与派生的概念继承与派生的概念第第4章章 继承与组合继承与组合图图4-1 4-1 单继承单继承中学生中学生学生学生初中生初中生高中生高中生专科生专科生本科生本科生研究生研究生 硕士生硕士生博士生博士生大学生大学生小学生小学生留学生留学生一个派生类只从一个基类派生,这称为单继承一个派生类只从一个基类派生,这称为单继承(single(single inheritance)inheritance),这种继承关系所形成的层次是一个树这种继承关系所形成的层次是一个
6、树形结构,可以用图形结构,可以用图4-14-1表示。表示。第第4章章 继承与组合继承与组合图图4-2 4-2 多继承多继承销售经理销售经理经理经理工人工人销售人员销售人员职员职员一个派生类不仅可以从一个基类派生,也可以从多个一个派生类不仅可以从一个基类派生,也可以从多个基类派生。基类派生。一个派生类有两个或多个基类的称为多重一个派生类有两个或多个基类的称为多重继承继承(multiple inheritance),这种继承关系所形成的这种继承关系所形成的结构如图结构如图4-2所示。所示。第第4章章 继承与组合继承与组合v基类和派生类的关系,可以表述为:基类和派生类的关系,可以表述为:派生类是基类
7、的具体化,而基类是派生类的抽象。派生类是基类的具体化,而基类是派生类的抽象。4.1 继承与派生的概念继承与派生的概念第第4章章 继承与组合继承与组合v单继承派生类的声明格式如下:单继承派生类的声明格式如下:vclass 派生类名派生类名:继承方式继承方式 基类名基类名vv 派生类新增加的成员派生类新增加的成员v;v其中,继承方式可以是其中,继承方式可以是public(公用的公用的)、private(私私有的有的)、protected(受保护的受保护的)。此项是可选的,如。此项是可选的,如果不写此项,则默认为果不写此项,则默认为private(私有的私有的)。4.2 派生类的声明方式派生类的声明
8、方式第第4章章 继承与组合继承与组合class Base /声明基类public:/基类公用成员 void setx(int n)x=n;int getx()return x;void showx()coutBase class:x=xendl;private:/基类私有成员 int x;第第4章章 继承与组合继承与组合/以public方式声明派生类Derived class Derived:public Basepublic:void sety(int n)y=n;int gety()return y;void showy()coutDerived class:y=yendl;private
9、:int y;第第4章章 继承与组合继承与组合v派生类中的成员派生类中的成员包括包括从基类继承过来的成员从基类继承过来的成员和和自己自己新增加的成员新增加的成员两大部分,从基类继承过来的成员体两大部分,从基类继承过来的成员体现了派生类从基类继承而获得的共性,而新增加的现了派生类从基类继承而获得的共性,而新增加的成员体现了派生类的个性,体现了派生类与基类的成员体现了派生类的个性,体现了派生类与基类的不同,体现了不同派生类的区别。不同,体现了不同派生类的区别。4.3 派生类的派生类的构成构成第第4章章 继承与组合继承与组合第第4章章 继承与组合继承与组合图图4-3 4-3 基类基类BaseBase
10、和派生类和派生类DerivedDerived的成员示意图的成员示意图 void setx();int getx();void showx();int x;Base类类 void setx();int getx();void showx();int x;Derived类类 void sety();int gety();void showy();int y;继承新增数据成员成员函数v实际上,并不是把基类的成员和派生类自己新增加实际上,并不是把基类的成员和派生类自己新增加的成员简单地加在一起就成为派生类。构造一个派的成员简单地加在一起就成为派生类。构造一个派生类一般经历生类一般经历3个步骤:个步骤:
11、1.从基类接收成员从基类接收成员 2.调整从基类接收的成员调整从基类接收的成员 3.增加新成员。增加新成员。4.3 派生类的派生类的构成构成第第4章章 继承与组合继承与组合v派生类中基类成员的访问属性派生类中基类成员的访问属性不仅不仅与在声明基与在声明基类时所声明的访问属性有关,类时所声明的访问属性有关,而且而且与在声明派与在声明派生类时所指定的对基类的继承方式有关生类时所指定的对基类的继承方式有关,这两,这两个因素共同决定基类成员在派生类中的访问属个因素共同决定基类成员在派生类中的访问属性。性。4.4 派生类中基类成员的访问属性派生类中基类成员的访问属性第第4章章 继承与组合继承与组合v派生
12、类对基类的继承方式有派生类对基类的继承方式有public,private和和protected 3种。不同的继承方式决定了基类成员在种。不同的继承方式决定了基类成员在派生类中的访问属性。派生类中的访问属性。v 简单地说:简单地说:v(1)公用继承公用继承(public inheritance)v 基类的公用成员和保护成员在派生类中保持原有基类的公用成员和保护成员在派生类中保持原有访问属性,其私有成员仍为基类私有。访问属性,其私有成员仍为基类私有。4.4 派生类中基类成员的访问属性派生类中基类成员的访问属性第第4章章 继承与组合继承与组合v(2)私有继承私有继承(private inherita
13、nce)v 基类的公用成员和保护成员在派生类中成了私有成基类的公用成员和保护成员在派生类中成了私有成员。其私有成员仍为基类私有。员。其私有成员仍为基类私有。4.4 派生类中基类成员的访问属性派生类中基类成员的访问属性第第4章章 继承与组合继承与组合v(3)受保护的继承受保护的继承(protected inheritance)v 基类的公用成员和保护成员在派生类中成了保护成基类的公用成员和保护成员在派生类中成了保护成员,其私有成员仍为基类私有。员,其私有成员仍为基类私有。v 保护成员的意思是保护成员的意思是:不能被外界访问,但可以被派不能被外界访问,但可以被派生类的成员访问。生类的成员访问。4.
14、4 派生类中基类成员的访问属性派生类中基类成员的访问属性第第4章章 继承与组合继承与组合v在在声明声明一个派生类时将基类的继承方式指定为一个派生类时将基类的继承方式指定为public的,称为的,称为公用继承公用继承。v用公用继承方式建立的派生类称为用公用继承方式建立的派生类称为公用派生类公用派生类(public derived class),其基类称为,其基类称为公用基类公用基类(public base class)。4.4.1 公用继承公用继承第第4章章 继承与组合继承与组合4.4.1 公用继承公用继承第第4章章 继承与组合继承与组合表表4-1 4-1 公用基类成员在派生类中的访问属性公用基
15、类成员在派生类中的访问属性公用基类的成员公用基类的成员在公用派生类中的访问属性在公用派生类中的访问属性私有成员私有成员不可访问不可访问公用成员公用成员公用公用保护成员保护成员保护保护第第4章章 继承与组合继承与组合【例例4-1】公用继承的例子。公用继承的例子。#include using namespace std;class Base /声明基类public:/基类公用成员 void setx(int n)x=n;int getx()return x;void showx()coutx=xendl;private:/基类私有成员 int x;/以public方式声明派生类Derived cl
16、ass Derived:public Basepublic:void sety(int n)y=n;int gety()return y;void showy()couty=yendl;void set(int m,int n)setx(m);/在Derived中x不可访问 y=n;第第4章章 继承与组合继承与组合 void show()/coutx=xendl;coutx=getx()endl;/showx();couty=yendl;private:int y;第第4章章 继承与组合继承与组合 int main()Derived obj;obj.setx(10);obj.showx();o
17、bj.sety(20);obj.showy();obj.set(30,40);obj.show();return 0;第第4章章 继承与组合继承与组合程序运行结果如下:程序运行结果如下:x=10 x=10y=20y=20 x=30 x=30y=40 y=40 v在声明一个派生类时将基类的继承方式指定为在声明一个派生类时将基类的继承方式指定为private的,称为的,称为私有继承私有继承。v用私有继承方式建立的派生类称为用私有继承方式建立的派生类称为私有派生类私有派生类(private derived class),其基类称为,其基类称为私有基类私有基类(private base class)。
18、4.4.2 私有继承私有继承第第4章章 继承与组合继承与组合4.4.2 私有继承私有继承第第4章章 继承与组合继承与组合表表4-2 4-2 私有基类成员在派生类中的访问属性私有基类成员在派生类中的访问属性私有基类的成员私有基类的成员在私有派生类中的访问属性在私有派生类中的访问属性私有成员私有成员不可访问不可访问公用成员公用成员私有私有保护成员保护成员私有私有第第4章章 继承与组合继承与组合【例例4-24-2】将将【例例4-14-1】中的公用继承方式改为中的公用继承方式改为 用私有继承方式用私有继承方式(基类基类BaseBase不变不变)。私有派生类如下私有派生类如下:/以private方式声明
19、派生类Derived class Derived:private Base public:void sety(int n)y=n;int gety()return y;void showy()couty=yendl;第第4章章 继承与组合继承与组合 void set(int m,int n)setx(m);/在Derived中x不可访问 y=n;void show()/getx()coutx=getx()endl;couty=yendl;private:int y;int main()Derived obj;/obj.setx(10);/obj.showx();obj.sety(20);obj
20、.showy();obj.set(30,40);obj.show();return 0;第第4章章 继承与组合继承与组合程序运行结果如下:程序运行结果如下:y=20y=20 x=30 x=30y=40 y=40 v由由protected声明的成员称为声明的成员称为“受保护的成员受保护的成员”,简,简称称“保护成员保护成员”。从类的用户角度来看,保护成员等。从类的用户角度来看,保护成员等价于私有成员。但有一点与私有成员不同,保护成员价于私有成员。但有一点与私有成员不同,保护成员可以被派生类的成员函数访问。可以被派生类的成员函数访问。4.4.3 保护成员和保护继承保护成员和保护继承第第4章章 继承
21、与组合继承与组合v在定义一个派生类时将基类的继承方式指定为在定义一个派生类时将基类的继承方式指定为protected的,称为的,称为保护继承保护继承。v用保护继承方式建立的派生类称为用保护继承方式建立的派生类称为保护派生类保护派生类(protected derived class),其基类称为受保护的基,其基类称为受保护的基类类(protected base class),简称,简称保护基类保护基类。4.4.3 保护成员和保护继承保护成员和保护继承第第4章章 继承与组合继承与组合第第4章章 继承与组合继承与组合表4-3 基类成员在派生类中的访问属性4.4.3 保护成员和保护继承保护成员和保护继
22、承基类中的基类中的成员成员在在公用派生类公用派生类中的访问属性中的访问属性在在私有派生类私有派生类中的访问属性中的访问属性在在保护派生类保护派生类中的访问属性中的访问属性私有成员私有成员不可访问不可访问不可访问不可访问不可访问不可访问公用成员公用成员公用公用私有私有保护保护保护成员保护成员保护保护私有私有保护保护通过以上的介绍,可以知道:通过以上的介绍,可以知道:v(1)在派生类中,成员有)在派生类中,成员有4种不同的访问属性:种不同的访问属性:v 公用的公用的:派生类内和派生类外都可以访问。:派生类内和派生类外都可以访问。v 受保护的受保护的:派生类内可以访问,派生类外不能访问,:派生类内可
23、以访问,派生类外不能访问,其下一层的派生类可以访问。其下一层的派生类可以访问。v 私有的私有的:派生类内可以访问,派生类外不能访问。:派生类内可以访问,派生类外不能访问。v 不可访问的不可访问的:派生类内和派生类外都不能访问。:派生类内和派生类外都不能访问。4.4.3 保护成员和保护继承保护成员和保护继承第第4章章 继承与组合继承与组合第第4章章 继承与组合继承与组合表表4-44-4派生类中的成员的访问属性派生类中的成员的访问属性派生类中的成员派生类中的成员在派生类在派生类中中在派生类在派生类外外在下层公用派在下层公用派生类中生类中派生类中访问属性派生类中访问属性为公用的成员为公用的成员可以可
24、以可以可以可以可以派生类中访问属性派生类中访问属性为受保护的成员为受保护的成员可以可以不可以不可以可以可以派生类中访问属性派生类中访问属性为私有的成员为私有的成员可以可以不可以不可以不可以不可以在派生类中不可访在派生类中不可访问的成员问的成员不可以不可以不可以不可以不可以不可以v(2)类的成员在不同作用域中有不同的访问属性类的成员在不同作用域中有不同的访问属性,对这一点要十分清楚。对这一点要十分清楚。4.4.3 保护成员和保护继承保护成员和保护继承第第4章章 继承与组合继承与组合第第4章章 继承与组合继承与组合【例例4-34-3】保护继承的例子。保护继承的例子。#include using n
25、amespace std;class Base /声明基类public:/基类公用成员 void setx(int n)x=n;void showx()coutx=xendl;protected:/基类保护成员 int getx()return x;private:/基类私有成员 int x;第第4章章 继承与组合继承与组合/以protected方式声明派生类Derived class Derived:protected Basepublic:void sety(int n)y=n;int gety()return y;void showy()couty=yendl;void set(int
26、m,int n)setx(m);/在Derived中x不可访问 y=n;第第4章章 继承与组合继承与组合 void show()/getx()coutx=getx()endl;couty=yendl;private:int y;int main()Derived obj;/obj.setx(10);/obj.showx();obj.sety(20);obj.showy();obj.set(30,40);obj.show();return 0;第第4章章 继承与组合继承与组合程序运行结果如下:程序运行结果如下:y=20y=20 x=30 x=30y=40 y=40 v在前面介绍派生类的构成时曾提
27、到:可以在派生类在前面介绍派生类的构成时曾提到:可以在派生类中声明一个与基类成员同名的成员,则派生类的新中声明一个与基类成员同名的成员,则派生类的新成员会屏蔽与其同名的基类成员,使同名的基类成成员会屏蔽与其同名的基类成员,使同名的基类成员成为员成为“不可见不可见”的,即基类成员的名字被隐藏。的,即基类成员的名字被隐藏。4.4.4 派生类对基类成员的重定义派生类对基类成员的重定义 和名字隐藏和名字隐藏第第4章章 继承与组合继承与组合第第4章章 继承与组合继承与组合【例例4-44-4】派生类重定义基类成员函数的例子。派生类重定义基类成员函数的例子。#include using namespace
28、std;class Base /声明基类public:/基类公用成员 void set(int n)x=n;void show()coutBase class:x=x endl;private:/基类私有成员 int x;第第4章章 继承与组合继承与组合/以public方式声明派生类Derived class Derived:public Basepublic:void set(int i,int j)m=i;n=j;void set(int i,int j,int k)/L1 访问从基类继承过来的同名成员函数set()Base:set(i);/L1 m=j;n=k;第第4章章 继承与组合继承
29、与组合 void show()/L2 访问从基类继承过来的同名成员函数show()Base:show();/L2 coutDerived class:m=mendl;coutDerived class:n=nendl;private:int m,n;int main()Derived obj;obj.set(1,2,3);/L3 obj.show();/L4 /obj.set(10);/L5错误,只能是obj.Base:set(10);obj.Base:set(10);/L6正确 obj.set(20,30);/L7 obj.show();/L8 obj.Base:show();/L9 ret
30、urn 0;第第4章章 继承与组合继承与组合程序运行结果如下:程序运行结果如下:Base class:x=1Base class:x=1Derived class:m=2Derived class:m=2Derived class:n=3Derived class:n=3Base class:x=10Base class:x=10Derived class:m=20Derived class:m=20Derived class:n=30Derived class:n=30Base class:x=10Base class:x=10从上例可以看出:从上例可以看出:v(1)如果是在派生类中声明了一
31、个与基类成员函)如果是在派生类中声明了一个与基类成员函数名字相同,参数也相同的成员函数,则基类中的数名字相同,参数也相同的成员函数,则基类中的成员函数将被隐藏。成员函数将被隐藏。v(2)如果是在派生类中声明了一个与基类成员函)如果是在派生类中声明了一个与基类成员函数名字相同,但参数不同的成员函数,则基类中的数名字相同,但参数不同的成员函数,则基类中的成员函数也将被隐藏。成员函数也将被隐藏。4.4.4 派生类对基类成员的重定义和名字隐藏派生类对基类成员的重定义和名字隐藏第第4章章 继承与组合继承与组合第第4章章 继承与组合继承与组合【例【例4-54-5】派生类重定义基类数据成员的例子。】派生类重
32、定义基类数据成员的例子。#include using namespace std;class Base /声明基类public:/基类公用成员 float y;void set(int n)x=n;void show()coutBase class:x=x endl;private:/基类私有成员 int x;第第4章章 继承与组合继承与组合/以public方式声明派生类Derived class Derived:public Basepublic:void set(int i,int j,int k)Base:set(i);y=j;z=k;void show()Base:show();cou
33、tBase class:y=Base:yendl;coutDerived class:y=yendl;coutDerived class:z=zendl;private:int y,z;int main()Derived obj;obj.set(1,2,3);obj.Base:y=12.3;obj.show();return 0;第第4章章 继承与组合继承与组合程序运行结果如下:程序运行结果如下:Base class:x=1Base class:x=1Base class:y=12.3Base class:y=12.3Derived class:y=2Derived class:y=2Deri
34、ved class:z=3Derived class:z=3v由于基类的构造函数和析构函数派生类是不能继承的。由于基类的构造函数和析构函数派生类是不能继承的。在声明派生类时,一般还应当自己定义派生类的构造在声明派生类时,一般还应当自己定义派生类的构造函数和析构函数。函数和析构函数。4.5 派生类的构造函数和析构函数派生类的构造函数和析构函数第第4章章 继承与组合继承与组合v构造函数的作用是在创建对象时对对象的数据成员进构造函数的作用是在创建对象时对对象的数据成员进行初始化。行初始化。派生类数据成员包括从基类继承过来的数派生类数据成员包括从基类继承过来的数据成员和自己新增加的数据成员,据成员和自
35、己新增加的数据成员,在设计派生类的构在设计派生类的构造函数时,造函数时,不仅要考虑派生类新增数据成员的初始化,不仅要考虑派生类新增数据成员的初始化,还应当考虑对其从基类继承过来的数据成员的初始化。还应当考虑对其从基类继承过来的数据成员的初始化。采取的方法是在执行派生类的构造函数时,调用基类采取的方法是在执行派生类的构造函数时,调用基类的构造函数。的构造函数。4.5.1 派生类构造函数派生类构造函数第第4章章 继承与组合继承与组合下面从最简单的派生类构造函数的定义说起。下面从最简单的派生类构造函数的定义说起。v所谓简单的派生类是指只有一个基类,而且只有一级所谓简单的派生类是指只有一个基类,而且只
36、有一级派生,在派生类的数据成员中不包含其他类对象的派派生,在派生类的数据成员中不包含其他类对象的派生类。简单的派生类构造函数的定义请看下面这个例生类。简单的派生类构造函数的定义请看下面这个例子:子:4.5.1 派生类构造函数派生类构造函数第第4章章 继承与组合继承与组合第第4章章 继承与组合继承与组合【例【例4-4-6 6】简单派生类的构造函数。简单派生类的构造函数。#includeusing namespace std;class Base /声明基类Basepublic:Base(int m,int n)x=m;y=n;/基类构造函数 Base()/基类析构函数 protected:/保护
37、部分 int x;int y;第第4章章 继承与组合继承与组合class Derived:public Base /声明公用派生类Derivedpublic:/派生类的共用部分 Derived(int m,int n,int k):Base(m,n)z=k;void show()coutx=xendl;couty=yendl;coutz=zendl;Derived()/派生类的析构函数private:/派生类的私有部分int z;int main()Derived obj(12,34,56);obj.show();/输出结果 return 0;第第4章章 继承与组合继承与组合程序运行结果如下:
38、程序运行结果如下:x=12x=12y=34y=34z=56z=56上例中派生类上例中派生类Derived的构造函数有的构造函数有3个形参,前个形参,前2个作个作为调用基类构造函数的实参,第为调用基类构造函数的实参,第3个为对派生类新增个为对派生类新增数据成员数据成员z初始化所需要的参数。其关系如图初始化所需要的参数。其关系如图4-4所示。所示。4.5.1 派生类构造函数派生类构造函数第第4章章 继承与组合继承与组合Derived(int m,int n,int k):Base(m,n)图图4-4 4-4 派生类派生类DerivedDerived的构造函数的参数传递的构造函数的参数传递 定义简单
39、派生类构造函数的一般形式为:定义简单派生类构造函数的一般形式为:():();4.5.1 派生类构造函数派生类构造函数第第4章章 继承与组合继承与组合在建立一个对象时,执行构造函数的顺序是在建立一个对象时,执行构造函数的顺序是:(1)最先调用基类的构造函数,对基类数据成员初始)最先调用基类的构造函数,对基类数据成员初始化。化。(2)再执行派生类构造函数的函数体,对派生类新增)再执行派生类构造函数的函数体,对派生类新增数据成员初始化。数据成员初始化。4.5.1 派生类构造函数派生类构造函数第第4章章 继承与组合继承与组合在使用派生类构造函数时,还有以下几种情况:在使用派生类构造函数时,还有以下几种
40、情况:v(1)多级派生的构造函数。一个类不仅可以派生出)多级派生的构造函数。一个类不仅可以派生出一个派生类,派生类还可以继续派生,形成派生的一个派生类,派生类还可以继续派生,形成派生的层次结构。在派生的层次结构中,每一层派生类的层次结构。在派生的层次结构中,每一层派生类的构造函数只负责调用其上一层(即它的直接基类)构造函数只负责调用其上一层(即它的直接基类)的构造函数。若在的构造函数。若在【例例4-6】的基础上由派生类的基础上由派生类Derived再派生出派生类再派生出派生类IndirectDerived,则派生,则派生类类IndirectDerived的定义如下:的定义如下:4.5.1 派生
41、类构造函数派生类构造函数第第4章章 继承与组合继承与组合vclass IndirectDerived:public Derivedvpublic:v IndirectDerived(int m,int n,int k,int):v Derived(m,n,k)w=p;v void show()v Derived:show();v coutw=wendl;v vprivate:v int w;v;4.5.1 派生类构造函数派生类构造函数第第4章章 继承与组合继承与组合v(2)当不需要对派生类新增的成员进行任何初始化)当不需要对派生类新增的成员进行任何初始化操作时,派生类构造函数的函数体可以为空,
42、即构操作时,派生类构造函数的函数体可以为空,即构造函数是空函数,如造函数是空函数,如【例例4-6】中派生类中派生类Derived的的构造函数可以改写为:构造函数可以改写为:v Derived(int m,int n,int k):Base(m,n)v此派生类构造函数的作用只是为了将参数传递给基此派生类构造函数的作用只是为了将参数传递给基类构造函数,并在执行派生类构造函数时调用基类类构造函数,并在执行派生类构造函数时调用基类构造函数。构造函数。4.5.1 派生类构造函数派生类构造函数第第4章章 继承与组合继承与组合v(3)如果基类中没有定义构造函数,或定义了没有)如果基类中没有定义构造函数,或定
43、义了没有参数的构造函数,那么在定义派生类构造函数时可参数的构造函数,那么在定义派生类构造函数时可以不写基类构造函数。在调用派生类构造函数时,以不写基类构造函数。在调用派生类构造函数时,系统会自动调用基类的默认构造函数。系统会自动调用基类的默认构造函数。v如果在基类中既定义了无参的构造函数,又定义了如果在基类中既定义了无参的构造函数,又定义了有参的构造函数(构造函数的重载),则在定义派有参的构造函数(构造函数的重载),则在定义派生类构造函数时,既可以包含基类构造函数及其参生类构造函数时,既可以包含基类构造函数及其参数,亦可以不包含基类构造函数。在调用派生类构数,亦可以不包含基类构造函数。在调用派
44、生类构造函数时,根据构造函数的内容决定调用基类的有造函数时,根据构造函数的内容决定调用基类的有参的构造函数还是无参的构造函数。我们可以根据参的构造函数还是无参的构造函数。我们可以根据派生类的需要决定采用哪一种方式。派生类的需要决定采用哪一种方式。4.5.1 派生类构造函数派生类构造函数第第4章章 继承与组合继承与组合v和构造函数一样,基类的析构函数派生类也不能继和构造函数一样,基类的析构函数派生类也不能继承。在声明派生类时,可以根据需要定义自己的析承。在声明派生类时,可以根据需要定义自己的析构函数,用来对派生类中新增加的成员进行清理工构函数,用来对派生类中新增加的成员进行清理工作。在执行派生类
45、的析构函数时,系统会自动调用作。在执行派生类的析构函数时,系统会自动调用基类的析构函数,对基类进行清理。派生类析构函基类的析构函数,对基类进行清理。派生类析构函数的执行顺序与构造函数正好相反:数的执行顺序与构造函数正好相反:v(1)最先执行派生类的析构函数的函数体,对派生)最先执行派生类的析构函数的函数体,对派生类新增加的成员进行清理。类新增加的成员进行清理。v(2)再调用基类的析构函数,对基类进行清理。)再调用基类的析构函数,对基类进行清理。4.5.2 派生类派生类析析构函数构函数第第4章章 继承与组合继承与组合第第4章章 继承与组合继承与组合【例【例4-4-7 7】派生类的析构函数。派生类
46、的析构函数。#includeusing namespace std;class Basepublic:Base()coutBase Constructorendl;Base()coutBase Destructorendl;第第4章章 继承与组合继承与组合class Derived:public Basepublic:Derived()coutDerived Constructorendl;Derived()coutDerived Destructorendl;int main()Derived obj;return 0;程序运行结果如下:程序运行结果如下:Base ConstructorBa
47、se ConstructorDerived ConstructorDerived ConstructorDerived DestructorDerived DestructorBase DestructorBase Destructorv多重继承多重继承(multiple inheritance,MI)是指派生类是指派生类具有两个或两个以上的直接基类具有两个或两个以上的直接基类(direct class)。)。4.6 多重继承多重继承第第4章章 继承与组合继承与组合v多重继承可以看做是单继承的扩展,派生类和每个多重继承可以看做是单继承的扩展,派生类和每个基类之间的关系可以看做是一个单继承。基类
48、之间的关系可以看做是一个单继承。多重继承多重继承派生类的声明格式如下:派生类的声明格式如下:vclass:,vv v;v其中不同的基类可以选择不同的继承方式。其中不同的基类可以选择不同的继承方式。4.6.1 声明多重继承的方法声明多重继承的方法第第4章章 继承与组合继承与组合v在多重继承方式下,定义派生类构造函数的一般形在多重继承方式下,定义派生类构造函数的一般形式如下:式如下:v():(),()vv v;v其中,其中,必须包含完成所有基类数据成员必须包含完成所有基类数据成员初始化所需的参数。初始化所需的参数。4.6.2 多重继承派生类的构造函数与析构函数多重继承派生类的构造函数与析构函数第第
49、4章章 继承与组合继承与组合v在建立一个派生类对象时,构造函数调用顺在建立一个派生类对象时,构造函数调用顺序为:序为:先调用所有基类的构造函数,再执行派生类先调用所有基类的构造函数,再执行派生类构造函数的函数体。构造函数的函数体。所有基类构造函数的调所有基类构造函数的调用顺序将按照它们在继承方式中的声明次序用顺序将按照它们在继承方式中的声明次序调用,而不是按派生类构造函数参数初始化调用,而不是按派生类构造函数参数初始化列表中的次序调用。列表中的次序调用。4.6.2 多重继承派生类的构造函数与析构函数多重继承派生类的构造函数与析构函数第第4章章 继承与组合继承与组合第第4章章 继承与组合继承与组
50、合【例【例4-4-8 8】多重继承派生类的构造函数。多重继承派生类的构造函数。#includeusing namespace std;class Base1 /声明基类Basepublic:/公用部分 Base1(int m,int n)x=m;y=n;/基类构造函数 void show1()/成员函数,输出基类数据成员 coutx=x y=yendl;protected:/保护部分 int x;int y;第第4章章 继承与组合继承与组合class Base2 /声明基类Base2public:/公用部分 Base2(int i,int j)u=i;v=j;/基类构造函数 void show