C++程序设计与数据结构基础:第6章 继承和派生类_第1页
C++程序设计与数据结构基础:第6章 继承和派生类_第2页
C++程序设计与数据结构基础:第6章 继承和派生类_第3页
C++程序设计与数据结构基础:第6章 继承和派生类_第4页
C++程序设计与数据结构基础:第6章 继承和派生类_第5页
已阅读5页,还剩32页未读 继续免费阅读

下载本文档

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

文档简介

1、第二部分第二部分 C+C+面向对象程序设计面向对象程序设计 本章内容本章内容 继承性、基类和派生类的基本概念继承性、基类和派生类的基本概念 派生类的定义和派生类对象的组成派生类的定义和派生类对象的组成 派生类的构造函数和析构函数派生类的构造函数和析构函数 虚基类虚基类 赋值兼容规则赋值兼容规则2 2 6.1 继承概述继承概述l 类与类之间的关系class B int a, b; public: B(int i, int j) a=i; b=j; class A int x; B bb; public: A( int i, int j, int k): bb (i, j), x( k ) ; 1

2、、“有有”关系(关系(has a)3 3#include class X friend class Y; int x; public: void set(int i) x=i; void Display()coutx=xendl; ; class Yint yy; public: Y(int,X&); void Display(X); ;2、“友友”关系(关系(friend)3、继承与派生、继承与派生“是是”关系(关系(is a)父子关系父子关系4 4继承的定义l 继承:在原有类(基类或父类)的基础上,经过适当扩充和完善建立新的类(派生类或子类) l 继承的本质是创建新的类 新类不仅具有基类的

3、特征,而且还可以添加新的特征,同时能够继续被继承而派生出新的类学生学生大学生大学生5 5继承的特点l 扩充和完善原有程序以适应新的需求。l 提高软件开发的效率,增加程序的重用性,减少代码和数据的冗余度。讨论:讨论:is a 和和has a的区别的区别6 6三种继承关系学生学生大学生大学生单重继承单重继承军校大学生军校大学生多重继承多重继承学生学生军人军人学生学生大学生大学生多级继承多级继承天津大学天津大学大学生大学生混合继承混合继承ACBDEF7 76.2 基类和派生类基类和派生类 l 定义派生类的格式class 派生类名: virtual 继承方式1 基类名1, virtual 继承方式2

4、基类名2, 派生类类体 ; 派生类类体中未定义的成员函数的实现 l 三种继承方式 public(公有继承) private(私有继承,缺省继承方式) protected(保护继承)8 8回顾:成员的访问权限回顾:成员的访问权限class A public: int a;void f1(); private: int b;void f2(); protected:int c;void f3();A x;/x是什么?是什么?x.a=10;/是否可以?是否可以?x.f1();/是否可以?是否可以?x.b=20;/是否可以?是否可以?x.f2();/是否可以?是否可以?x.c=30;/是否可以?是否可

5、以?x.f3();/是否可以?是否可以?/成员函数定义成员函数定义void A:f1() b=20; /是否可以?是否可以?如果不考虑继承,保护成员和私有成员的地位是一样的。私有和保护成员只能被该类成员函数直接访问。保护成员和私有成员的区别在于前者能被继承。9 9public公有继承方式公有继承方式class A public: int a;void f1(); private:int b;void f2(); protected:int c;void f3();class B: public A int d;void f4();public: int e;void f5();讨论:讨论: B

6、 B有几个成员?有几个成员? 各是什么权限?各是什么权限?类类B中:中: 公有成员:公有成员:int a;void f1();int e;void f5();保护成员:保护成员:int c;void f3();私有成员:私有成员:int b;void f2();int d;void f4();1010说明:在公有继承下,l 直接基类的公有成员和保护成员分别作为派生类中的公有成员和保护成员。l 直接基类的私有成员也会被继承,但派生类不能直接访问直接基类的私有成员。只能通过直接基类的公有成员函数和保护成员函数间接访问它们。l 派生类的对象只能直接访问直接基类的公有成员。void B:f5() a=

7、10; b=10; c=10; d=10; e=10; f2(); f3();void A:f3() b=10; B x;x.a=100; x.e=200;x.f1();1111private私有继承方式私有继承方式class A public: int a;void f1(); private:int b;void f2(); protected:int c;void f3();class B: private A int d;void f4();public: int e;void f5();直接基类的公有成员直接基类的公有成员和保护成员均作为派和保护成员均作为派生类的生类的私有成员私有成

8、员。类类B中:中:公有成员:公有成员:int e;void f5();私有成员:私有成员:int a;void f1();int c;void f3();int b;void f2();int d;void f4();私有继承方式是默认的继承方式:私有继承方式是默认的继承方式:class B:A1212protected保护继承方式保护继承方式class A public: int a;void f1(); private:int b;void f2(); protected:int c;void f3();class B: protected A int d;void f4();public

9、: int e;void f5();直接基类的公有成员和直接基类的公有成员和保护成员均作为派生类保护成员均作为派生类的的保护成员保护成员。类类B中:中:公有成员公有成员: int e;void f5();保护成员保护成员:int a;void f1();int c;void f3();私有成员私有成员:int d;void f4();int b;void f2();1313不可直接访问不可直接访问privateprivateprivate不可直接访问不可直接访问protectedprotectedprotected不可直接访问不可直接访问protectedpublicpublicprivate

10、protectedpublic基类特性基类特性派生类特性派生类特性继承方式继承方式不同继承方式下基类与派生类的特性不同继承方式下基类与派生类的特性 1414派生类对象的数据成员组成1515派生类本身数据成员(除静态数据成员外)子对象m数据成员(除静态数据成员外)子对象2数据成员(除静态数据成员外).子对象1数据成员(除静态数据成员外)直接基类n数据成员(除静态数据成员外).直接基类2数据成员(除静态数据成员外)直接基类1数据成员(除静态数据成员外)例6.5 画出下面程序中类C对象obj1的组成结构图 class C :public Bpublic: void f3(); protected:

11、static int j3; void g3(); private: int i3; ;int C:j3;class A public: int k1; void f1(); protected: static int j1; void g1(); private: int i1; void h1();int A:j1;class B :public Apublic: void f2(); protected: int j2; void g2(); private: static int i2; A a1,a2; void h2();int B:i2;1616Bj2Ai1k1A a1i1k1A

12、a2i1k1B的子对象的子对象a2的数据成员的数据成员C的的数数据据成成员员B的的数数据据成成员员B的子对象的子对象a1的数据成员的数据成员B的直接基类的直接基类A的数据成员的数据成员Ci317176.3 派生类的构造函数与析构函数派生类的构造函数与析构函数 l 派生类构造函数的一般形式派生类构造函数的一般形式派生类构造函数名(总参数表): 直接基类初始化表,子对象初始化表, 派生类自身数据成员初始化表 派生类构造函数体 直接基类初始化表的形式为: 直接基类1构造函数 (参数表1), 直接基类2构造函数 (参数表2), 子对象初始化表形式为: 子对象名1(参数表1),子对象名2(参数表2),

13、派生类自身数据成员初始化表形式为: 数据成员名1(参数1),数据成员名2(参数2), 1818class A int x; public: A() x=0; /缺省构造函数缺省构造函数 A( int k) x=k; ; class A int x; public: A() x=0; /数据成员初始化表数据成员初始化表 A( int k) : x(k) ; class B int a, b; public: B() a=2; b=5; B(int i, int j) a=i; b=j; ; class A int x; B bb; public: A() x=0; /子对象初始化表子对象初始化表

14、 A( int i, int j, int k): bb (i, j), x( k ) ; class B int a, b; public: B() a=2; b=5; B(int i, int j) a=i; b=j; ; class A : public B int x; B bb; public: A() x=0; /直接基类初始化表直接基类初始化表 A( int i1, int j1, int i, int j, int k): B(i1, j1), bb (i, j), x( k ) ; 1919各直接基类 派生类自身数据成员 各子对象(定义时的顺序) (定义时的顺序) l 派生类

15、构造函数的执行顺序派生类构造函数的执行顺序2020派生类本身数据成员(除静态数据成员外)子对象1数据成员(除静态数据成员外)子对象2数据成员(除静态数据成员外).子对象m数据成员(除静态数据成员外)直接基类1数据成员(除静态数据成员外)直接基类2数据成员(除静态数据成员外).直接基类n数据成员(除静态数据成员外)P173 例例6.6 #include class Base public: Base() a=0; coutBase缺省构造函数缺省构造函数n; Base(int i)a=i;coutBase构造函数构造函数n; void print()couta=a,; int Geta()ret

16、urn a; private: int a; ;class Derived: public Base public: Derived()b=0; coutDerived缺省构造函数缺省构造函数n; Derived (int i, int j, int k): Base(i), Ba(j), b(k) cout“Derived 构造函数构造函数n”; void print() Base:print(); /调用基类调用基类Base的的print()函数函数 coutb=b,Ba.a=Ba.Geta()endl; private: int b; Base Ba; /子对象或称为内嵌对象子对象或称为

17、内嵌对象 ; void main() Derived d1, d2(5,3,7); d1.print(); d2.print(); b 0Base Ba a 0Base a 0d1组成结构图组成结构图b 7Base Ba a 3Base a 5d2组成结构图组成结构图程序输出结果程序输出结果 :Base缺省构造函数缺省构造函数 Base缺省构造函数缺省构造函数 Derived缺省构造函数缺省构造函数 Base构造函数构造函数 Base构造函数构造函数 Derived构造函数构造函数 a=0,b=0,Ba.a=0a=5,b=7,Ba.a=3 2121l 派生类析构函数派生类析构函数 派生类析构函

18、数的形式无特殊之处,不必显式地调用各直接基类 各子对象相应类的析构函数,这些操作是由系统自动完成的 执行各析构函数的顺序恰好与执行各构造函数的顺序相反。22222323直接基类直接基类1数据成员数据成员直接基类直接基类2数据成员数据成员.直接基类直接基类n数据成员数据成员子对象子对象1数据成员数据成员子对象子对象2数据成员数据成员.子对象子对象m数据成员数据成员派生类本身数据成员派生类本身数据成员各直接基类 派生类自身数据成员 各子对象(定义时的顺序) (定义时的顺序) 单重继承派生类析构函数示例单重继承派生类析构函数示例 #include class Base public: Base()

19、a=0; Base(int i) a=i; void print()couta=a,; int Geta()return a; Base()coutBase(a=a)析构函数析构函数n; private: int a; ; class Derived: public Basepublic: Derived()b=0; Derived(int i,int j,int k):Base(i),Ba(j)b=k; Derived() coutDerived(b=b)析构函数析构函数n; void print() Base:print(); coutb=b,Ba.a=Ba.Geta()endl; pri

20、vate: int b; Base Ba; ; void main() Derived d1,d2(5, 3, 7); d1.print(); d2.print(); 程序输出结果程序输出结果 :a=0,b=0,Ba.a=0 a=5,b=7,Ba.a=3 Derived(b=7)析构函数析构函数 Base(a=3)析构函数析构函数 Base(a=5)析构函数析构函数 Derived(b=0)析构函数析构函数 Base(a=0)析构函数析构函数 Base(a=0)析构函数析构函数 2424例6.10 多重继承中构造函数和析构函数示例 #include class base1 int i1; pu

21、blic: base1(int i) i1=i; coutbase1(i1=i1)构造函数构造函数n; base1() coutbase1(i1=i1)析构函数析构函数n; ; class base2 int i2; public: base2(int i) i2=i; coutbase2(i2=i2)构造函数构造函数n; base2() coutbase2(i2=i2)析构函数析构函数n; ;class derived: public base1, public base2base1 b1; base2 b2; int i3; public: derived(int j1, int j2,

22、int j3, int j4, int j5) :base2(j2), base1(j1), b2(j3), b1(j4) i3=j5; coutderived构造函数构造函数n; derived() coutderived析构函数析构函数n; ; void main() derived d(5,4,3,2,1); 程序输出结果程序输出结果 : base1(i1=5)构造函数构造函数 base2(i2=4)构造函数构造函数 base1(i1=2)构造函数构造函数 base2(i2=3)构造函数构造函数 derived构造函数构造函数 derived析构函数析构函数 base2(i2=3)析构函

23、数析构函数 base1(i1=2)析构函数析构函数 base2(i2=4)析构函数析构函数 base1(i1=5)析构函数析构函数 25256.3.3 虚基类虚基类 l 多重继承中的二义性问题 派生类对象通过不同继承路径而得到两个或两个以上同名成员 的问题。struct A void f1() coutXixixin; ; struct B void f1() cout“Hahahan; ; struct C:public A, public B ; 声明:C x;调用x.f1()会发生什么? 解决方法一:使用成员名限定来消除二义性。如调用x.B:f1(); 方法二:成员函数重定义struct

24、 C:public A, public B void f1() cout“Gegegen”; /B:f1(); ; /成员函数重定义2626l 多级继承中的二义性问题 class A public: int na; void fun() coutfun() of A(na=na)n; ; class B: public A public: int nb; ; class C: public A public: int nc; ; class D: public B, public C public: int nd; ; 继承关系继承关系DABACd d的组成结构图的组成结构图BA nanbCA

25、 nancndvoid main() D d; d.B:na=2; d.C:na=3; coutd.B:A:na=d.B:na; coutnd.C:A:na=d.C:na; coutendl; d.B:fun(); d.C:fun(); 程序输出结果程序输出结果 :d.B:A:na=2d.C:A:na=3 fun() of A(na=2) fun() of A(na=3) 2727l 虚基类:不希望结果具有二义性;希望只有一份间接基类的成员被继承下来 。则可以把间接基类转为虚基类class A public: int na; void fun() coutfun() of A(na=na)n;

26、 ; class B: virtual public A public: int nb; ; class C: virtual public A public: int nc; ; class D: public B, public C public: int nd; ; d d的组成结构图的组成结构图BnbCA nancndvoid main() D d; d.na=3; coutd.nad.naendl; d.fun(); 程序输出结果程序输出结果 :d.na=3fun() of A(na=3) 2828l 虚基类的构造函数和析构函数 虚基类的数据成员只被初始化一次 。 在一个基类初始化表

27、中,若同时出现对虚基类和非虚基类构造函数的调用,则虚基类的构造函数优先执行。若同时包括多个虚基类,则按它们在定义派生类时说明的顺序调用各虚基类的构造函数。 p248例8.11 虚基类构造、析构函数调用示例 2929class A public: A() coutA classn; A()coutclass An; ; class D1 public: D1() cout“D1 classn; D1()coutclass D1n; ; class D2: public D1, virtual public A public: D2() cout“D2 classn; D2()coutclass

28、D2n; ; class D3: public D1, virtual public A public: D3() cout“D3 classn; D3()coutclass D3n; ; class D4: public D2, virtual public D3 public: D4() cout“D4classn; D4()coutclass D4n; ; void main() D4 d;D4D1D2AD3程序输出结果 :A classD1 classD3 classD1 classD2 classD4 classclass D4class D2class D1class D3clas

29、s D1class A30306.4 赋值兼容规则 class Aint m, n;class B ;main()A x;B y;/什么情况下可以?什么情况下可以?x=y;l 不同类型的对象之间的转换结论:1、B必需是A的派生类。2、B对A必需是公有继承的3131赋值兼容规则 l 赋值兼容规则 赋值兼容规则:是指在公有继承的前提下,基类对象与公有派生类对象之间的自动类型转换和赋值的规则。 规则只对公有继承有效。如果对私有继承或保护继承使用,则会出现语法错误。 由于派生类中包含从基类继承的成员,所以可以将派生类对象赋值给基类对象,在需要基类对象的任何时候都可以其用派生类对象代替。 赋值兼容规则主

30、要包括两个内容:基类对象与派生类对象之间的关系;基类对象的指针与派生类对象的指针之间的关系。3232基类对象与派生类对象之间的关系1.可以用派生类对象给基类对象赋值,反之不行 。2.可以用派生类对象初始化基类对象或基类的引用。 如果函数的形参是基类对象或基类对象的引用,则对应的实参可以是派生类的对象。3.可以把派生类对象的地址赋给指向其基类对象的指针变量。反之不行。4. 可以把派生类对象的指针赋值给基类对象的指针。反之则错。base b;derived d;b=d;d=b; /错derived d;base b(d);base &rb=d;base b, *pb;derived d, *pd;pb=&d;pd=&b; /错base *pb;derived d, *pd=&d;pb=pd;pd=pb; /错3333#include class A int x;public: A(int x1)x=x1; void print() coutx=x ; ;class B: public A int y;public: B(int

温馨提示

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

评论

0/150

提交评论