版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第四章 派生类与继承 4.1 派生类的概念 4.2 派生类的构造函数和析构函数 4.3 调整基类成员在派生类中的访问属性的其他方法 4.4 多重继承 4.5 基类与派生类对象之间的赋值兼容关系 本章主要内容4.1 派生类的概念 4.1.1 为什么要使用继承 4.1.2 派生类的声明 4.1.3 派生类的构成 4.1.4 基类成员在派生类中的访问属性 4.1.5 派生类对基类成员的访问规则 本节主要内容4.1 4.1 派生类的概念派生类的概念4.1.1 4.1.1 为什么要使用继承为什么要使用继承图图4.1 4.1 简单的汽车分类图简单的汽车分类图 汽车汽车运输汽车运输汽车专用汽车专用汽车客车客
2、车货车货车消防车消防车洒水车洒水车 所谓继承就是从所谓继承就是从先辈处得到属性和行先辈处得到属性和行为特征。为特征。 假设有两个类-类A 和类B,若类B继承类A A (基类或父类) B (派生类或子类) 则类B具有类A的基本特性(包括数据和程序代码) 类的继承就是新的类从已有类那里得到已有的特性。 继承机制的作用: 类的继承机制使程序员无需修改已有类,只需在已有类的基础上,通过增加少量代码或修改少量代码的方法得到新的类,从而较好地解决了代码重用的问题。 由已有类产生新类时,新类便包含了已有类的特征,同时也可以加入自己的新特性。 如果类B是类A 的派生类,那么,在构造类B的时候: 1.不必重新描
3、述派生类B的所有特性,只需让它继承类A的特性; 2. 增加类B与基类A不同的那些特性。 继承来的特性 派生类的特性 新增加的特性4.1.2 派生类的声明class person class employeeprotected: protected: string name ; string name; int age; int age; char sex; char sex; public: string department; void print(); float salary; ; public: void print1(); ; 相同部分相同部分 class person class
4、employee:public person protected: protected: string name; string department; int age; float salary; char sex; public: public: void print1(); void print(); ; ; 完整程序见书P138被继承被继承的部分的部分新增加新增加的部分的部分基类基类名名派生类名派生类名类类基类基类名名继承继承方式方式 声明一个派生类的一般格式为: class 派生类名继承方式 基类名 /派生类新增的数据成员和成员函数 ; class employeepublic pe
5、rson / ; class employeeprivate person / ; class employeeprotected person / ; 默认的继承方式为:private 公有继承公有继承私有继承私有继承保护继承保护继承4.1.3 派生类的构成 派生类Employee和基类Person的关系 :构造一个派生类一般包括以下三部分工作: (1) 派生类从基类接收成员 在C+的类继承中,派生类把基类的全部成员(除构造函数和析构函数之外)接收过来。 (2) 调整从基类接收来的成员 对基类成员的调整包括两个方面: 一方面是改变基类成员在派生类中的访问属性,这主要是通过派生类声明时的继承方
6、式来控制的。 另一方面是派生类可以对基类的成员进行重定义。 (3) 在派生类中增加新的成员 可以根据实际情况的需要,精心设计需要增加的数据成员和成员函数,来实现必要的新增功能。 以上所述构造派生类三部分工作的具体实现方法将在下面章节中详细介绍。 4.1.4 基类成员在派生类中的访问属性 class A private: int x; public: int y; protected: int z; ; class B :private(或public,protected)A . . ;问题:基类成员问题:基类成员x x、y y、z z的访问的访问属性在派生类中有什么变化属性在派生类中有什么变化
7、? ? 基类成员基类成员x x、y y、z z在派生类中访问属在派生类中访问属性的变化是与继承性的变化是与继承的方式有关的。的方式有关的。1. 私有继承时class A private: int X; public: int Y; protected: int Z; ; class B : private A X 不允许派生类继承,不可直接访问。 Y 在派生类中以私有成员的身份出现 Z 在派生类中以私有成员的身份出现。 私有继承私有继承 2.公有继承时class A private: int X; public: int Y; protected: int Z; ; class B : pub
8、lic A X 不允许派生类继承,不可直接访问。 Y 在派生类中仍以公有成员的身份出现 Z 在派生类中仍以保护成员的身份出现 公有继承公有继承3.保护继承时class A private: int X; public: int Y; protected: int Z; ; class B : protected A X 不允许派生类继承,不可直接访问。 Y 在派生类中以保护成员的身份出现 Z 在派生类中仍以保护成员的身份出现 保护保护继承继承4.1.5 派生类对基类成员的访问规则 派生类对基类成员的访问形式主要有以下两种:class A public: int x;class B : 派生方式
9、 A print() coutx; ; int main( ) B b1; coutb1.x; return 0; 内部访问内部访问 由派生类中新由派生类中新增的增的成员函数成员函数对基类继承来对基类继承来的成员的访问的成员的访问 对象访问对象访问 在派生类外部在派生类外部, ,通过通过派生类的对象派生类的对象对从基类继对从基类继承来的成员的访问承来的成员的访问class A int x; public: int y; protected: int z; ;class B :private A print() /访问x ?,y?,z? (内部访问); main( ) B b1; /b1 访问x
10、?,y ?,z? (对象访问) . . .私有继承私有继承1. 私有继承的访问规则 此表不要死记此表不要死记#include / / 例例4.14.1class base / / 声明一个基类声明一个基类 int x; public: void setx(int n) x=n; void showx( ) coutxendl; ;class derived:private base / / 声明一个私有派生类声明一个私有派生类 private: int y; public: void setxy(int n,int m) setx(n); y=m; void showxy( ) coutxen
11、dl; coutyendl; ;私有私有继承继承setx()setx()在派生类中为私有成员在派生类中为私有成员, , 派派生类成员函数生类成员函数setxy()setxy()可以访问它可以访问它 非法非法, ,基类中的私有基类中的私有成员成员x x, , 不允许派生类不允许派生类成员函数成员函数showxy()showxy()直接直接访问它访问它 main() derived obj; obj.setx(10); obj.showx(); obj.setxy(10,20); obj.showxy( ); return 0; 非法非法, ,setx()setx()在派生类中在派生类中为私有成员
12、为私有成员, ,派生类对象派生类对象objobj不能访问不能访问 非法非法, ,showx()showx()在派生类中在派生类中为私有成员为私有成员, ,派生类对象派生类对象objobj不能访问不能访问class A int x; public: int y; protected: int z; ;class B : public A print() /访问x ?,y?,z? (内部访问); main( ) B b1; /b1 访问x?,y ?,z? (对象访问) . . .公有继承公有继承2. 公有继承的访问规则 此表不要死记此表不要死记#include /例例4.34.3class bas
13、e /声明一个基类声明一个基类 private: int x; protected: int y; public: void setxy(int m,int n) x=m; y=n; void showxy() coutx=xendl; couty=yendl; ;class derived: public base /声明一个公有派生类声明一个公有派生类 private: int z; public: void setxyz(int m,int n,int l) setxy(m,n); z=l; void showxyz() coutx=xendl; couty=yendl; coutz=z
14、endl; ;公有继承公有继承setxy()setxy()在派生类中在派生类中是公有成员是公有成员, ,派生类派生类成员函数成员函数setxyz()setxyz()可以访问它可以访问它非法非法, ,x x在派生类中为在派生类中为不可直接访问成员不可直接访问成员 合法合法, ,y y在派生类中在派生类中为保护成员为保护成员, ,派生类派生类成员函数成员函数showxyz()showxyz()可以访问它可以访问它main() derived obj; obj.setxyz(30,40,50); obj.showxy(); obj.showxyz(); obj.y=60; return 0; 合法合
15、法, ,showxy()showxy()在派生类在派生类中为公有成员中为公有成员, ,派生类对象派生类对象objobj可以访问可以访问错误,错误,Y Y在派生类中是保护在派生类中是保护成员,派生类对象不能访问成员,派生类对象不能访问class A int x; public: int y; protected: int z; ;class B : protected A print() / 访问x ?,y?,z? (内部访问); main( ) B b1; / b1 访问x?,y ?,z? (对象访问) . . . 保护继承保护继承3. 保护继承的访问规则 例例4.4 4.4 (自学,教材(自
16、学,教材P148P148) 对于基类中的私有成员: 无论哪种派生方式,基类中的私有成员, 不允许派生类的对象直接访问(对象访问), 不允许派生类中成员函数直接访问(内部访问) , 但是可以通过基类提供的公有成员函数访问。 4.2 派生类的构造函数和析构函数4.2.1 派生类构造函数和析构函数的执行顺序4.2.2 派生类构造函数和析构函数的构造规则本节主要内容4.2.1 派生类构造函数和析构函数的 执 行 顺 序 通常情况下: 当创建派生类对象时: 基类的构造函数派生类的构造函数; 当撤消派生类对象时: 派生类的析构函数基类的析构函数。 #include /例4.5-1 class base p
17、ublic: base() cout基类的构造函数n base() cout基类的析构函数n; ;class derive:public base public: derive( ) cout派生类的构造函数n; derive( ) cout派生类的析构函数n;main( ) derive op; return 0; 运行结果如下:运行结果如下:基类的构造函数基类的构造函数 派生类的构造函数派生类的构造函数 派生类的析构函数派生类的析构函数 基类的析构函数基类的析构函数 4.2.2 派生类构造函数和析构函数的构造规则1. 1. 简单的派生类的构造函数简单的派生类的构造函数 当基类的构造函数没有
18、参数,或没有显式定义构造函数时,派生类可以不向基类传递参数,甚至可以不定义构造函数。 当基类含有带参数的构造函数时,派生类必须定义构造函数,以提供把参数传递给基类构造函数的途径。#include /例4.5-1 class base public: base() cout基类的构造函数n“; base() cout基类的析构函数n; ;class derive:public base public: derive( ) cout派生类的构造函数n; derive( ) cout派生类的析构函数n;main( ) derive op; return 0; 基类的构造函数没有参数基类的构造函数没有
19、参数不需要缀上不需要缀上“: :基类名基类名( (参数表参数表) ) ”问题的引入问题的引入 问题问题: :当基类的构当基类的构造函数造函数带有参数时带有参数时,对构造函数又有什对构造函数又有什么要求呢么要求呢? ?#include class base public: int x; base(int a) cout基类的构造函数n“;x=a; base() cout基类的析构函数n; ;class derive:public base public: derive(int i ):base(i) cout派生类的构造函数n; derive( ) cout派生类的析构函数n;main( ) d
20、erive op(5); return 0; 基类的构造函数带有参数基类的构造函数带有参数缀上缀上“: :基类名基类名( (参数表参数表) ) ” 当基类含有带参数当基类含有带参数的构造函数时,派生的构造函数时,派生类必须定义构造函数,类必须定义构造函数,并并缀上缀上“: :基类名基类名( (参参数表数表) ) ”, ,以提供把参以提供把参数传递给基类构造函数传递给基类构造函数的途径。数的途径。 在C+中,派生类构造函数的一般格式为: 其中基类构造函数参数表的参数,通常来源于派生类构造函数的参数表,也可以用常数值。 派生类名派生类名( (参数总表参数总表) ):基类名基类名( (参数表参数表)
21、 ) 派生类新增成员的初始化语句派生类新增成员的初始化语句 #include /例例4.6-14.6-1class base int i; public: base(int n) cout调用基类的构造函数n; i=n; base() cout调用基类的析构函数n; void showi() coutiendl; ;class derive :public base int j; public: derive(int a,int b):base(b) cout调用派生类的构造函数nendl; j=a; derive() cout调用派生类的析构函数nendl; void showj( ) co
22、utjendl; ;main() derive obj(30,40); obj.showi(); obj.showj(); return 0; 基类含有带参数的构造函数基类含有带参数的构造函数 定义派生类构造函定义派生类构造函数时,缀上数时,缀上“: :基类名基类名( (参数表参数表) ) ”程序运行结果为:程序运行结果为: 调用基类的构造函数调用基类的构造函数 调用派生类的构造函数调用派生类的构造函数 40 40 30 30 调用派生类的析构函数调用派生类的析构函数 调用基类的析构函数调用基类的析构函数 说明: (1)可以将派生类构造函数定义在类的外部,而在类体内只写该函数的声明。 例如:
23、在派生类中声明构造函数的原型: derive(int a,int b); 而在类的外部定义派生类的构造函数: derive(int a,int b):base(b) cout调用派生类的构造函数nendl; j=a; 在此,不包括基类在此,不包括基类构造函数名及其参数构造函数名及其参数表表( (即即:base(b):base(b) )在此,要列出基类构造函数在此,要列出基类构造函数名及其参数表名及其参数表( (即即:base(b):base(b) ) 。 (2) 若基类使用不带参数的构造函数或带缺省参数的构造函数,则在派生类中定义构造函数时可略去“基类(参数表)”; class Aclass
24、A . . . . . . A() A() . . . . . .;class B:Aclass B:A. . . . . B() . . . B() . . .;(3) 当基类构造函数不带参数时,派生类不一定需要定义构造函数,然而当基类的构造函数哪怕只带有一个参数,它的派生类都必须定义构造函数,并缀上“基类(参数表)”,甚至所定义的派生类构造函数的函数体可能为空,仅仅起参数的传递作用。 class Aclass A . . . . . . A(int x ) A(int x ) . . . . . .;Class B:AClass B:A. . . . . B( int x,int y):
25、B( int x,int y):A(x)A(x) . . . . . . ; ; 例如,在下面的程序段中,派生类Derived不使用参数n,n只是被传递给了基类构造函数Base。class Base public: Base(int n) coutConstructing base classn; i=n; void showi() coutin; private: int i;class Derived:public Base public: Derived(int n):Base(n) ; 在此,派生类构造函数在此,派生类构造函数的的函数体为空函数体为空, , 参数参数n n只是只是被传递
26、给了基类构造函数被传递给了基类构造函数BaseBase。 (4)如果派生类的基类也是一个派生类,每个派生类只需负责其直接基类的构造,依次上溯。 (4)如果派生类的基类也是一个派生类,每个派生类只需负责其直接基类的构造,依次上溯。 class Aclass A . . . . . . A(int x ) A(int x ) . . . ; . . . ;class B:class B:A A . . . . . B( int x,int y): B( int x,int y):A(x)A(x) . . . . . . ; ;class C:class C:B B . . . . . C( int
27、 x,int y,int z): C( int x,int y,int z):B(x,y)B(x,y) . . . . . . ; ; (4)如果派生类的基类也是一个派生类,每个派生类只需负责其直接基类的构造,依次上溯。 class Aclass A . . . . . . A(int x ) A(int x ) . . . ; . . . ;class B:class B:A A . . . . . B( int x,int y): B( int x,int y):A(x)A(x) . . . . . . ; ;class C:class C:B B . . . . . C( int x,i
28、nt y,int z): C( int x,int y,int z):B(x,y)B(x,y) . . . . . . ; ; 2派生类的析构函数 在派生类中可以根据需要定义自己的析构函数,用来对派生类中的所增加的成员进行清理工作,基类的清理工作仍然由基类的析构函数负责。 在执行派生类的析构函数时,系统会自动调用基类的析构函数,对基类的对象进行清理。 #includeclass base public: . . . base() cout基类的析构函数n; ;class derive:public base public: . . . derive() cout派生类的析构函数n;main(
29、) derive op; return 0; 析构函数是析构函数是不带参数的不带参数的, ,在在派生类中是否派生类中是否要自定义析构要自定义析构函数与它所属函数与它所属基类的析构函基类的析构函数无关,它们数无关,它们各自是独立的。各自是独立的。 3. 含有对象成员(子对象)的派生类的构造函数 class base int x; public: base(int i); /基类的构造函数 /. . . ;class derived:public base base d; public: derived() /. . . ; d d为基类对为基类对象,作为派生象,作为派生类的对象成员类的对象成员问
30、题问题:当派生类中:当派生类中含有对含有对象成员象成员时时, ,其构造函数应其构造函数应该如何构造该如何构造? ? 当派生类中含有对象成员时,其构造函数的一般形式为: 定义派生类对象时,构造函数的执行顺序如下: 调用基类的构造函数, 对基类数据成员初始化; 调用对象成员的构造函数,对对象成员的数据成员初始化; 执行派生类的构造函数体,对派生类数据成员初始化。 派生类名派生类名( (参数总表参数总表) ):基类名基类名( (参数表参数表0)0),对象对象名成员名成员1 1( (参数表参数表1)1),对象成员名对象成员名n n ( (参数表参数表n)n) /派生类新增成员的初始化语句派生类新增成员
31、的初始化语句 . . 例例4.8-1 4.8-1 派生类构造函数和析构函数的执行顺序。派生类构造函数和析构函数的执行顺序。#includeclass base int x; public: base(int i) x=i; cout基类的构造函数n; base( ) cout基类的析构函数n; void show( ) cout x= xendl; ;class derived:public base base d; /d为基类对象,作为派生类的对象成员 public: derived(int i):base(i),d(i) cout派生类的构造函数n; derived( ) cout派生类的
32、析构函数n; ;main( ) derived obj(5); obj.show( ); return 0; 派生类的构造函数,缀派生类的构造函数,缀上要调用的基类构造函数和上要调用的基类构造函数和对象成员构造函数对象成员构造函数 定义派生定义派生类对象时类对象时, ,构构造函数的执行造函数的执行顺序如下顺序如下: : 调用基类调用基类的构造函数的构造函数; ;调用对象调用对象成员的构造函成员的构造函数数; ;执行派生执行派生类的构造函数类的构造函数体体。例例4.8-1 4.8-1 派生类构造函数和析构函数的执行顺序。派生类构造函数和析构函数的执行顺序。#includeclass base i
33、nt x; public: base(int i) x=i; cout基类的构造函数n; base( ) cout基类的析构函数n; void show( ) cout x= xendl; ;class derived:public base base d; /d为基类对象,作为派生类的对象成员 public: derived(int i):base(i),d(i) cout派生类的构造函数n; derived( ) cout派生类的析构函数n; ;main( ) derived obj(5); obj.show( ); return 0; 派生类的构造函数,缀派生类的构造函数,缀上要调用的基
34、类构造函数和上要调用的基类构造函数和对象成员构造函数对象成员构造函数 撤消对象撤消对象时,析构函数时,析构函数的调用顺序与的调用顺序与构造函数的调构造函数的调用顺序正好相用顺序正好相反反。 . .调用派生类调用派生类的析构函数的析构函数; ; . . 调用对象调用对象成员的析构函成员的析构函数数; ; . . 调用基类调用基类的析构函数。的析构函数。例例4.8-1 4.8-1 派生类构造函数和析构函数的执行顺序。派生类构造函数和析构函数的执行顺序。#includeclass base int x; public: base(int i) x=i; cout基类的构造函数n; base( ) c
35、out基类的析构函数n; void show( ) cout x= xendl; ;class derived:public base base d; /d为基类对象,作为派生类的对象成员 public: derived(int i):base(i),d(i) cout派生类的构造函数n; derived( ) cout派生类的析构函数n; ;main( ) derived obj(5); obj.show( ); return 0; 程序执行结果如下:程序执行结果如下:基类的构造函数基类的构造函数 基类的构造函数基类的构造函数 派生类的构造函数派生类的构造函数 x=5 x=5 派生类的析构函
36、数派生类的析构函数 基类的析构函数基类的析构函数 基类的析构函数基类的析构函数 4.3 调整基类成员在派生类中的访问属性的其他方法 4.3.1 同名成员 4.3.2 访问声明 本节主要内容 4.3.1 同名成员 在定义派生类的时候,C+语言允许在派生类中说明的成员与基类中的成员名字相同,也就是说,派生类可以重新说明与基类成员同名的成员。 class X public: int f() ; class Y:public X public: int f(); int g(); ; void Y:g( ) f(); void main( ) Y obj; obj.f(); 同名成员同名成员访问哪个类
37、中的访问哪个类中的f()?f()? C+规定:如果在派生类中定义了与基类成员同名的成员,则派生类成员覆盖了基类的同名成员访问哪个类中的访问哪个类中的f()?f()? class X public: int f() ; class Y:public X public: int f(); int g(); ; void Y:g( ) f(); void main( ) Y obj; obj.f(); C+规定:如果在派生类中定义了与基类成员同名的成员,则派生类成员覆盖了基类的同名成员 表示访问派生类中表示访问派生类中的的f(),f(),即被调用的函数即被调用的函数是是Y:f()Y:f()被访问的函
38、数是被访问的函数是Y:f()Y:f() class X public: int f() ; class Y:public X public: int f(); int g(); ; void Y:g( ) f(); void main( ) Y obj; obj.f(); 问题问题: :若要访问基类若要访问基类中的中的f(),f(),怎么办?怎么办? class X public: int f() ; class Y:public X public: int f(); int g(); ; void Y:g( ) X:f(); void main( ) Y obj; obj.f(); 被访问的
39、函数是被访问的函数是Y:f()Y:f() 若要访问基若要访问基类中的类中的f(),f(),可可改改写成写成X:f()X:f()4.2.3 访问声明#include /#include /例例4.10-1 4.10-1 using namespace std;using namespace std;class Aclass A int x; int x; public: public: A(int x1) x=x1; A(int x1) x=x1; void print( ) coutx=x;void print( ) coutx=x; ; ; class B:public Aclass B:p
40、ublic A int y; int y; public: public: B( int x1,int y1):A(x1) y=y1; B( int x1,int y1):A(x1) y=y1; ; ; main( ) main( ) B b(10,20); B b(10,20); b.print( );b.print( ); return 0; return 0; 公有派生公有派生执行结果执行结果: :X=10X=10正确!正确!例4.10_2 #includeclass A int x;私有派生私有派生 public: A(int x1)x=x1; void print( )coutx=x
41、; ; class B: private A int y; public: B(int x1,int y1):A(x1)y=y1; ; main( ) B b(10,20); b.print(); return 0; 私有派生私有派生#include /#include /例例4.10-2 4.10-2 using namespace std;using namespace std;class Aclass A int x; int x; public: public: A(int x1)x=x1; A(int x1)x=x1; void print( )coutx=x;void print(
42、 )coutx=x; ; ; class B: private Aclass B: private A int y; int y; public: public: B(int x1,int y1):A(x1)y=y1; B(int x1,int y1):A(x1)y=y1; ; ; main( ) main( ) B b(10,20); B b(10,20); b.print();b.print(); return 0; return 0; 私有继承私有继承出现错误!出现错误!问题的提出:问题的提出: 能否使能否使私有继承私有继承的的派生类的对象派生类的对象访问基类访问基类的的公有成员公有成员
43、或或保护成员保护成员。例例4.10_34.10_3#include#includeclass Aclass A int x;int x; public: public: A(int x1)x=x1; A(int x1)x=x1; void print( )coutx=x;void print( )coutx=x; ;class B:private Aclass B:private A int y; int y; public: public: B(int x1,int y1):A(x1)y=y1; B(int x1,int y1):A(x1)y=y1; void print2( ) print
44、( );void print2( ) print( ); ;main( )main( ) B b(10,20); B b(10,20); b.print2( );b.print2( ); return 0; return 0; 派生类的对象派生类的对象通通过过派生类的公有成派生类的公有成员函数员函数和和基类的公基类的公有成员函数有成员函数间接访间接访问问私有继承私有继承的基类的基类的的公有成员公有成员或或保护保护成员成员。执行结果执行结果: :X=10X=10私有继承私有继承解决方法1 :通过公有成员函数间接访问 class A . . . public: void print( ) . .
45、. ; class B:private A public: A:print; ; 访问声明:访问声明: 把基类的把基类的保护成员名保护成员名或或公有成员名公有成员名直接写到私有派直接写到私有派生类定义式中的同名段中,生类定义式中的同名段中, 同时在成员名前冠以同时在成员名前冠以“基类名基类名” 。 利用这种方法利用这种方法, ,该成员就该成员就成为派生类的保护成员或公成为派生类的保护成员或公有成员了。有成员了。 函数函数print()print()调整为调整为派生类的公有成员派生类的公有成员访问声明访问声明解决方法2:使用访问声明私有继承私有继承例例4.11_14.11_1#include#i
46、ncludeclass Aclass A int x; int x; public: public: A(int x1)x=x1; A(int x1)x=x1; void print( )coutx=x;void print( )coutx=x; ;class B: private Aclass B: private A int y; int y; public: public: B(int x1,int y1):A(x1)y=y1; B(int x1,int y1):A(x1)y=y1; A:print;A:print; ;main( )main( ) B b(10,20); B b(10,
47、20); b.print( ); b.print( ); return 0; return 0; 私有继承私有继承访问声明访问声明: :把基类中把基类中的函数的函数print()print()调整调整为派生类的公有成员为派生类的公有成员执行结果执行结果: :X=10X=10 说明: 访问声明中只能含不带类型和参数的函数名或变量名。 例如: A:print ; void A:print; A:print(); 都是错误的 void A:print(); 数据成员也可以使用访问声明,例如: class A public: int x2; ; class B : private A public:
48、A:x2; . ; 把基类中的把基类中的数据成员数据成员x2x2调整为派生类的公有成员调整为派生类的公有成员 访问声明不能改变类成员在基类中原来的性质。 class A class B: private A private: private: int x1; A:x1; /错误 protected: protected: int x2; A:x1; /错误 public: A:x2; /正确 int x3; A:x3; /错误 ; public: A: x1; /错误 A: x2; /错误 A: x3; /正确 ; /练习题练习题2 2#include#includeclass Aclass
49、A int x; int x; public: public: A(int x1)x=x1; A(int x1)x=x1; void print( )coutx=x;void print( )coutx=x; void print(int a=0)couta=a; void print(int a=0)couta=a; ; ;class B:private Aclass B:private A int y; int y; public: public: B(int x1,int y1):A(x1)y=y1; B(int x1,int y1):A(x1)y=y1; A:print;A:print
50、; ; main( )main( ) B b(10,20); B b(10,20); b.print();b.print(); return 0; return 0; 二义性二义性 对于基类中的重载函数使用访问声明时要慎重。 4.4 4.4 多重继承多重继承 4.4.1 4.4.1 多重继承的声明多重继承的声明 4.4.2 4.4.2 多重继承的构造函数与析构函数多重继承的构造函数与析构函数 4.4.3 4.4.3 虚基类虚基类本节主要内容 4.4.1 多重继承的声明 当一个派生类具有多个基类时,这种派生方法称为多重派生或多重继承。 4.4.1 多重继承的声明 当一个派生类具有多个基类时,这种
51、派生方法称为多重派生或多重继承。 基类1基类2派生类 多重继承声明的一般形式如下: class class 派生类名:派生类名:继承方式继承方式1 1 基类名基类名1 1, 继承方式继承方式n n 基类名基类名n n 派生类新增的数据成员和成员函数派生类新增的数据成员和成员函数 ; class zclass z:private xprivate x,public y public y / / ; class zclass z:public x ,y public x ,y / / ; 类类z z私有继承了类私有继承了类x x,公有继承了类公有继承了类y y 类类z z公有继承了类公有继承了类x
52、, x, 私有继承了类私有继承了类y y 在多重继承中在多重继承中, ,各种继承方式对于基类成员在各种继承方式对于基类成员在派生类中的访问属性和规则与单继承相同派生类中的访问属性和规则与单继承相同。 #include#include/例例4.13-14.13-1class Xclass X int a; int a; public: public: void setX(int x) a=x; void setX(int x) a=x; void showX( ) couta=aendl; void showX( ) couta=aendl; ;class Yclass Y int b; int
53、 b;public:public: void setY(int x) b=x; void setY(int x) b=x; void showY()coutb=bendl; void showY()coutb=bendl; ; class Z :public X,private Yclass Z :public X,private Y int c; int c; public: public: void setZ(int x,int y) void setZ(int x,int y) setY(x); c=y; setY(x); c=y; void showZ( ) showY( ); cou
54、tc=cendl; void showZ( ) showY( ); coutc=cendl; ;void main( ) Z obj; obj.setX(3); obj.showX( ); obj.setY(4); obj.showY( ); obj.setZ(6,8); obj.showZ( ); 这两条语句出现错误这两条语句出现错误 删去标有错误的语句,删去标有错误的语句,程序运行结果如下:程序运行结果如下: a=3a=3 b=6 b=6 c=8 c=8class Xclass X / /思考题:思考题: publicpublic: int f()int f(); ;class Yclas
55、s Y public public: int f()int f(); int g()int g(); ;class Zpublic Xclass Zpublic X,public Ypublic Y public public: int g()int g(); int h()int h(); ;main( )main( ) Z obj; Z obj; obj.f() obj.f(); 二义性二义性! ! 对基类成员的访问必须对基类成员的访问必须是无二义的,如程序段对基是无二义的,如程序段对基类成员的访问是二义的,必类成员的访问是二义的,必须想法消除二义性。须想法消除二义性。访问哪个类中的访问哪
56、个类中的f()?f()? 使用成员名限定可以消除二使用成员名限定可以消除二义性,例如:义性,例如: obj.Xf()obj.Xf();/调用类调用类X X的的f()f() obj.Yf() obj.Yf();/调用类调用类Y Y的的f()f() 4.4.2 多重继承的构造函数与析构函数 多重继承构造函数定义的一般形式如下: 派生类名派生类名( (参数总表参数总表) ):基类名基类名1(1(参数表参数表1)1),基类名基类名2(2(参数表参数表2)2),基类名基类名n(n(参数表参数表) ) 派生类新增成员的初始化语句派生类新增成员的初始化语句 class Hardclass Hard prot
57、ected protected: char bodyname20char bodyname20; publicpublic: Hard(char Hard(char * *bdnm)bdnm); /基类基类HardHard构造函数构造函数 / ; class Softclass Soft protected protected: char os10, Lang15char os10, Lang15; publicpublic: Soft(char Soft(char * *o,char o,char * *lg);lg); /基类基类SoftSoft的构造函数的构造函数 / ; class S
58、ystemclass System:public Hardpublic Hard,public Softpublic Soft char owner10 char owner10; publicpublic: System(char System(char * *owow,char char * *bnbn,char char * *o o,char char * *lg)lg) Hard(bn)Hard(bn),Soft(o,lg)Soft(o,lg); / ; 例例: :由一个硬件类由一个硬件类HardHard和一个软件类和一个软件类SoftSoft,它们共同派生出系统类,它们共同派生出系
59、统类SystemSystem 派生类派生类SystemSystem的构造函数的构造函数缀上了要调用的基类缀上了要调用的基类HardHard和和SoftSoft的构造函数的构造函数例例P168末行末行 多重继承构造函数的执行顺序与单继承构造函数的执行顺序相同: 先执行基类的构造函数; 再执行对象成员的构造函数; 最后执行派生类构造函数。 析构函数的执行顺序则刚好与构造函数的执行顺序相反。 #include /例例4.14-14.14-1class X int a; public: X(int sa) a=sa; int get_a( ) return a; ;class Y int b; pub
60、lic: Y(int sb) b=sb; int get_b( ) return b; ;class Z:public X,private Y int c; public: Z(int sa,int sb,int sc):X(sa),Y(sb) c=sc; int get_c( ) return c; int get_b( ) return Y:get_b(); ; main( ) Z obj(2,4,6);couta= obj.get_a()endl;coutb= obj.get_b()endl;coutc= obj.get_c()endl; return 0; 基类基类X X的构造函数的构
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 精.品解析:粤教版七年级下册地理 第八章 欧洲 单元练习(解析版)
- 火灾基础技术4
- 军工企业配套产品数据泄露的国防安全风险与物理隔离与载体销毁与审计对策
- 白介素-10在施万细胞免疫抑制表型转化中的作用机制结题报告
- T∕CSTC 34.6-2025 香蕉全产业链标准综合体 第6部分:加工技术
- 心血管考研试题及答案
- 空调压缩机配件生产车间扩建项目可行性研究报告模板立项申批备案
- 建筑施工应急管理规定
- 2025年光伏行业人工薪酬成本涨幅
- 2026年文物保护工程从业资格实务考试冲刺模拟试题
- 湖北省高速公路改扩建施工路域环境提升指南(试行)2025
- 政府公务接待培训课件
- 幼儿园健康饮食指导方案及营养食谱
- 尾矿库施工方案安全措施与实施步骤试题及答案
- APQP第三版及CP第一版介绍
- 尼康coolpix4500使用说明书
- 物种互作关系研究-洞察及研究
- 2026年中考英语专题复习:常考必背热点话题作文满分范文汇编
- 非营业性演出管理办法
- 优抚政策培训课件下载
- 2025年广东省高考政治试卷真题(含答案解析)
评论
0/150
提交评论