C++程序设计第12章-继承和派生课件_第1页
C++程序设计第12章-继承和派生课件_第2页
C++程序设计第12章-继承和派生课件_第3页
C++程序设计第12章-继承和派生课件_第4页
C++程序设计第12章-继承和派生课件_第5页
已阅读5页,还剩39页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第 12 章 继承和派生12.1 继承的基本概念 12.2 单一继承 12.3 多重继承 12.4 基类成员的初始化 12.5 二义性和支配规则 12.6 虚基类 12.7 访问基类成员和访问对象成员的成员 12.8 赋值兼容 第 12 章 继承和派生 继承提供了在已有类的基础上开发出新类的机制,可以节省重复代码的编写工作,是软件重用的基础。 B AA派生类是对基类的扩充12.1 继承的基本概念已知一个类A,对A类加以扩展,即增加一些属性和行为,构成一个新类B,此时B类将A类已有的属性和行为继承下来。称类 B 继承了 A ,或称类 A 派生了 B 。A :父类,基类 BaseClassB :子

2、类,派生类 DerivedClass在校人员类学生类职工类( 属性:姓名,年龄,身高 ) 增加属性: 学号 成绩 增加属性: 部门 工资 单一继承多重继承圆柱体类 圆类 高度类 组合(属性: 圆心坐标,半径) (属性: 高度)属性: 圆心坐标,半径 ,高度在C+中,有两种继承方式:单一继承和多重继承。 12.2 单一继承定义派生类的一般格式:class : private: / 私有成员说明 . public: / 公有成员说明 . protected: / 保护成员说明 . ; 继承方式:public 公有继承(派生) private 私有继承(派生) protected 保护继承(派生)定

3、义派生类新成员12.2.1 公有继承(派生) A B class A . ;class B: public A / 公有继承A . ;A 类中的 public 和 protected 成员,在B 中仍然保持其原访问特性。虽然A中的私有成员也被继承下来了,但在B中不可直接访问。A 中的: 在 B 中: 在B的类外(通过对象) private 成员 不可访问 不可访问public成员 仍为 public 成员 可访问protected成员 仍为 protected 成员 不可访问相当于对B类做如下定义: class B: private: int bx;protected: int ay; int

4、 by;public: int az; int bz; void f1( ).; int Getax( ). void Setax( int x ) ax = x; void f2( ).; float f3( ).;private int ax;例如: 继承关系如下:class A private: int ax;protected: int ay;public: int az; void f1( ).; int Getax( )return ax; void Setax( int x ) ax = x; ;class B: public A private: int bx;protecte

5、d: int by;public: int bz; void f2( ).; float f3( ).;蓝色斜体是从A类继承的成员在 B 的成员函数中可直接访问A类的ay,az,f1( ),Getax( ),Setax( )相当于对B类做如下定义: class B: private: int bx;protected: int ay; int by;public: int az; int bz; void f1( ).; int Getax( ). void Setax( int x ) ax = x; void f2( ).; float f3( ).;private int ax;例如:

6、继承关系如下:class A private: int ax;protected: int ay;public: int az; void f1( ).; int Getax( )return ax; void Setax( int x ) ax = x; ;class B: public A private: int bx;protected: int by;public: int bz; void f2( ).; float f3( ).;在B类中不可直接访问A类的成员ax可通过 Getax( )、Setax( )访问A类的私有成员 ax 的值注意:在main( )函数中,只定义一个Cir

7、cle类对象:int main( )Circle c(0, 0, 2);c.ShowCircle( );c.Move(2, 2);c.ShowCircle( );c.Setxy(0, 0); /重新置圆心坐标 c.Setr(1); /重新置半径值c.ShowCircle( );return 0; 使用一个Circle类对象 c 时,感觉Circle类是一个完整的类,就象 Point 类不存在一样。 如Setxy( ) 函数,它是在基类中被定义的,现在它就是Circle类的成员了,但在Circle类中并没有写出它的实现函数,代码是被继承下来的。例12.1见 “第12章 继承和派生(例子).doc

8、x” 面向对象程序设计中继承性的优点就在于此,系统提供了相当多的已定义好的基类,用户可以根据具体的应用,在已有类的基础上构架新类,在派生类中,可以直接使用父类部分的代码,但却不需要重新编写父类的代码。这样可以加速软件开发的速度,保障软件开发的质量。继承性是软件重用的基础。 在一个类上仅构架一个新类,意义并不大。但如果构架多个新类,那么就可以减少大量相同代码的重复编写工作。如从一个“点”类可以派生出“线”类、“圆”类、“长方形”类等。 从本例中,还可以看出另一个问题:为了实现数据保护,在基类中将 x, y 定义为私有成员,但是带来一个问题,即在派生类中需通过公有成员函数Getx( ) ,Setx

9、y(x1, y1) 等来访为基类的私有成员。 如果在基类中将 x, y 定义为保护成员,则公有继承后,在派生类中x, y 仍然是保护成员,在派生类内可直接访问。这样既可以保护基类数据成员,又可以在派生类中提供访问基类数据成员的方便性。12.2.2 私有继承(派生) A B class A . ;class B: private A / 私有继承A . 将 A 中的 public 和 protected 成员均变成了B 的 private 成员。同理,A中的私有成员被继承下来了,但在B中不可直接访问,A 中的: 在 B 中: 在类外(类B的对象中) private 成员 不可访问 不可访问pub

10、lic成员 变为 private 成员 不可访问protected成员 变为 private 成员 不可访问相当于对B类做如下定义: class B: private: int bx; int ay; int az; void f1( ).; int Getax( ). void Setax( int x ) ax = x; protected: int by;public: int bz; void f2( ).; float f3( ).;private int ax;例如: 继承关系如下:class A private: int ax;protected: int ay;public:

11、int az; void f1( ).; int Getax( )return ax; void Setax( int x ) ax = x; ;class B: private A private: int bx;protected: int by;public: int bz; void f2( ).; float f3( ).;蓝色斜体是从A类继承的成员在 B 的成员函数中可直接访问A类的ay,az,f1( ),Getax( ),Setax( )相当于对B类做如下定义: class B: private: int bx; int ay; int az; void f1( ).; int

12、Getax( ). void Setax( int x ) ax = x; protected: int by;public: int bz; void f2( ).; float f3( ).;private int ax;例如: 继承关系如下:class A private: int ax;protected: int ay;public: int az; void f1( ).; int Getax( )return ax; void Setax( int x ) ax = x; ;class B: private A private: int bx;protected: int by;

13、public: int bz; void f2( ).; float f3( ).;在B类中不可直接访问A类的成员ax可通过 Getax( )、Setax( )访问A类的私有成员 ax 的值12.2.3 保护继承(派生) A B class A . ;class B: protected A / 保护继承A . A 中的: 在 B 中: 在类外(类B的对象中) private 成员 不可访问 不可访问public成员 变为 protected 成员 不可访问protected成员 变为 protected成员 不可访问将 A 中的 public 和 protected 成员均变成了B 的 pr

14、otected 成员。同理,A中的私有成员被继承下来了,但在B中不可直接访问,由于“私有继承” 和“保护继承”用得不多,在这里不再详细叙述了。 无论何种继承方式,private成员是无法在派生类中被直接访问的。而对于protected成员,根据不同的派生方式,protected成员的直接访问特性可以被(或不被)传递到派生类的派生类中。 12.2.4 private成员和protected成员的区别 1对于公有派生,基类的protected成员在派生类中依然保持protected属性。2对于私有派生,基类的protected成员在派生类中变成了private成员,此时基类的protected成员

15、就再也无法在派生类的派生类中被直接访问了。在继承或派生链中,一旦出现私有继承,则父类的成员的“类内直接访问特性”就无法在后面的派生中传递下去。3对于保护派生,基类的protected成员在派生类中依然保持protected属性,此时情况与公有派生类似。类中protected成员的优点是:既可以在本类中实现数据的隐藏(在类外不可被直接访问),又可以将其类内直接访问特性传递到派生类中(在派生类中可直接访问)。但private成员只能实现本类中的数据隐藏,而不能将其类内直接访问特性传递到派生类中。 12.3 多重继承一般格式:class : , , /以下定义派生类新成员 private: / 私有

16、成员说明 . public: / 公有成员说明 . protected: / 保护成员说明 . ;多个基类派生一个类多重继承Circle 类Point类 Radius类 组合再次说明保护成员的优点例12.2 见 “第12章 继承和派生(例子).docx”注意例12.2的D行,若一个类是由多个基类派生出来的,则在定义派生类构造函数时,应调用基类的构造函数,以初始化基类成员。 12.4 基类成员的初始化12.4.1 基类的构造函数和析构函数的调用顺序 派生类构造函数的一般格式:ClassName : ClassName(args) : Base1(arg1) , Base2(arg2) , . B

17、asen(argn) ;其中ClassName是派生类名,Base1、Base2、.Basen为基类的类名。args是派生类自身的构造函数的形参列表,arg1、arg2、.argn是调用基类构造函数的实参列表。 析构函数的调用顺序为:(相反)先执行派生类自身的析构函数体、然后按 Basen( ) 、.Base2( ) 、Base1( )例12.3 见 “第12章 继承和派生(例子).docx”构造函数的调用顺序为: Base1( )、 Base2( )、. Basen( )、最后执行。 在例12.3中:调用基类的构造函数的顺序并不是B行的书写顺序决定的,而是A行定义派生类时的派生顺序决定的,即

18、使将B行改写成Derived(int x, int y, int z) : Base2(y), Base1(x),程序的运行结果依然不变。 12.4.2 对象成员构造函数和析构函数的调用顺序 例12.4 见 “第12章 继承和派生(例子).docx”或见下一页简化例子:若派生类中包含对象成员,则在派生类的构造函数的初始化成员列表中:不仅要列举基类的构造函数,而且要列举对象成员的构造函数class Base1 int data1;public: Base1(int a)data1=a; .;class Base2 int data2; public: Base2(int a)data2=a; .

19、 ;class Derived: public Base1, public Base2 /公有继承基类 int d; Base1 b1, b2; /对象成员public: Derived(int a, int b):Base1(a), Base2(20),b1(200),b2(a+b) d=a; .先调用基类的构造函数再调用对象成员的构造函数最后执行对象自身的构造函数问题见下页问题:对本例,一个Derived类的对象有几个数据成员?(包括自身具备的、和继承来的? )返回12.5 二义性和支配规则12.5.1 二义性(多重继承带来的访问冲突)例12.5class A protected: int

20、 x;public: A(int a) x=a; .;class B protected: int x;public: B(int a) x=a; .;class C: public A, public B /公有继承 A 和 B int y;public: void Setx(int a) x=a; .;当基类 A和 B 中出现两个同名的成员 x 时,在派生类中访问 x 出现二义性问题:一个类C的对象有几个数据成员?class A protected: int x;public: A(int a) x=a; .;class B protected: int x;public: B(int a

21、) x=a; .;class C: public A, public B /公有继承 A 和 B int y;public: void Setx(int a) x=a; .;解决办法:将此句改为:A:x = a; 或 B:x = a;同理:解决基类同名成员函数的访问class C: public A, public B /公有继承 A 和 Bint y;public:void SetAx(int a) A:x=a;/对类A中的x置值void SetBx(int a) B:x=a;/对类B中的x置值void Sety(int b) y=b; int Gety( ) return y; ;int

22、main( )C c1;c1.SetAx(35);c1.SetBx(45);c1.Sety(300);coutY=c1.Gety( )endl;return 0;例12.6 部分代码,解决访问冲突 C A B 注意:如何解决冲突 (访问二义性)。当把派生类作为基类,又派生出新的派生类时,这种限定作用域的运算符不能连续嵌套使用,如下形式的使用方式是不允许的: : : : 例12.7 见 “第12章 继承和派生(例子).docx”如何解决多层继承中的冲突,请看下例:由于C+是通过作用域运算符来解决访问二义性问题,因此规定任一基类在派生类中只能被直接继承一次,否则会造成成员名访问的冲突。例如:cla

23、ss A public: float x; .;class B: public A, public A /错误的. ;B类的定义是错误的,因为如果直接从A类继承两次,通过作用域运算符就无法解决访问二义性问题。 12.5.2 支配规则例12.8 支配规则示例 见 “第12章 继承和派生(例子).docx”问题:类 C 有几个数据成员。基类和派生类出现同名成员时,派生类成员访问优先-支配规则12.6 虚基类 类D 基类B 基类C 基类A 基类A 如右图的公有继承关系中, 在类 D 中包含了基类 A 的 两个拷贝。 在类 D 的成员函数中, 欲访问 A 的成员 x , 则必须以 B:x 和 C:x

24、区分。 B DA C A一个D类对象的存储空间 若欲使公共的基类A 在派生类中只有一个拷贝, 如右图, 可将 A 说明成虚基类。 说明的方法: 继承时,在基类的类名前 加上关键词:virtual 类D 基类B 基类C 基类A 例12.10 虚基类的例子见下页: B D C A一个D类对象的存储空间 class A protected: int x; public: A(int a=0) x=a; ;class B: virtual public A protected: int y; public: B(int a=0, int b=0):A(a) y=b; ;class C: public

25、virtual A protected: int z; public: C(int a=0, int c=0):A(a) z=c; ;注意: virtual 的位置。class D: public B, public C protected: int k; B(a1, b), C(a2, c), k(d) public: D(int a1=0, int a2=0, int b=0, int c=0, int d=0) : void Show( )cout x= x , ; cout y= y , ;cout z= z , ;cout k= k endl;int main(void)D obj(

26、1, 1, 2, 3, 4);obj.Show( );return 0; 发挥 程序的运行结果是:x=0, y=2, z=3, k=4问题:类 D 有几个数据成员?B 和 C 的构造函数中,分别调用 A的构造函数,编译器无法确定调用哪一个来初始化A,在这种情况下,约定直接调用 A 的缺省构造函数。(即使 a1 和 a2 的值相等)如将G行改为:D(int a1=0, int a2=0, int b=0, int c=0, int d=0) : B(a1, b), C(a2, c), A(a1), k(d) /G 则程序的运行结果变为: x=1, y=2, z=3, k=4 注意:如果派生类有多个基类,有些是虚基类有些是非虚基类。则基类构造的调用顺序是先调用虚基类的构造函数再调用非虚基类的构造函数,并按照继承顺序调用。直接调用虚基类的构造函数例12.11 见 “第12章 继承和派生(例子).docx”在成员函数中:(1) 使用基类的成员 (2) 使用对象成员的成员时,情况不同12.7 访问基类成员和访问对象成员的成员class A public: int x; A(int

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论