C++课件C++_第九章_第1页
C++课件C++_第九章_第2页
C++课件C++_第九章_第3页
C++课件C++_第九章_第4页
C++课件C++_第九章_第5页
已阅读5页,还剩41页未读 继续免费阅读

下载本文档

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

文档简介

1,第9章 继承与派生,9.1 类的层次与继承性 9.2 派生类 9.3 派生类的构造函数和析构函数 9.4 多重继承 9.5 赋值兼容 9.6 派生类的编程原则 9.7 小结,2,9.1 类的层次与继承性,继承是描述类的层次性的机制,继承的过程称为派生。 派生类(也称子类)继承它父类的属性和操作。子类也声明了新的属性和新的操作。,3,4,/person类 (人): class person private : char name10; int age; char sex; public: void showinfo( ); ;,/ employee类 (职员) : class employee private : char name10; int age; char sex; char department20; float salary; public: void showinfo( ); ;,5,9.2 派生类,9.2.1 派生类的声明 已有的类称为基类,由基类继承而来的类称为派生类。 C+中派生类定义的一般形式是: class 派生类名 : 派生方式 基类名 派生类新增加数据成员; 派生类新增加成员函数; ;,6,其中: 派生方式关键字为private、public或protected,分别表示私有继承、公有继承和保护继承。缺省的继承方式(即没有显示声明)是私有继承。 派生类成员是指除了从基类继承来的成员外,新增加了数据成员和成员函数。通过新增加成员来实现代码的复用和功能的扩充。,7,说明: 1.派生方式有private、public或protected 2.基类(或父类)和派生类(子类) 3.直接基类和间接基类 4.派生类具有的成员 5.派生和继承是同一个问题的不同表述 class A int a; ; class B:public A int b; ,8,通过继承和派生改写employee class person private : char name10; int age; char sex; public: void showinfo( ); ;,class employee :public person private : char department20; float salary; ;,9,9.2.2 派生类的访问控制权限 注意:类的不可访问成员不能被任何函数访问,可以被继承传递下去,10,class A private: int s; public: void inits(int n) s=n; int gets( ) return s; void sets(int a) s=a; ;,class B: public A private: int t; public: void initt(int n) t=n; int getts( ) return t*gets(); void sett(int a) t=a; ;,11,void main( ) B ob; ob.sets(12); ob.sett(5); coutob.getts( )endl; 一定要熟练掌握继承方式,12,派生类生成过程(派生类的编程步骤),吸收基类成员,改造基类成员,发展新成员,重写构造函数与析构函数,全盘接收父类成员(除构造函数与析构函数),添加和父类同名成员,即覆盖(override),添加新的与父类成员不同名的成员,13,9.3.1 派生类构造函数和析构函数的执行顺序 对于创建对象,先执行基类的构造函数,再执行派生类中对象成员的构造函数,最后执行派生类的构造函数。 对于释放对象,先执行派生类的析构函数,再执行派生类中对象成员的析构函数,最后执行基类的析构函数。,9.3 派生类的构造函数和析构函数,14,9.3.2派生类构造函数和析构函数的设计 派生类构造函数和析构函数设计的原则 如果基类定义了带有形参表的构造函数,派生类就必须定义新的构造函数,提供一个将参数传递给基类构造函数的途径,以便保证在基类进行初始化时能获得必需的数据。 如果派生类的基类也是派生类,则每个派生类只需负责其直接基类的构造,不负责自己的间接基类的构造。 派生类是否要定义析构函数与所属的基类无关,如果派生类对象在撤销时需要做清理善后工作,就需要定义新的析构函数。,15,2. 派生类构造函数的设计 派生类名派生类名(参数总表):基类名(参数表),新增对象成员名1(参数表1),新增对象成员名n(参数表n) /派生类新增成员的初始化语句 派生类的构造函数负责类内所有成员的构造,16,3. 派生类析构函数的设计 派生类析构函数的功能与基类析构函数的功能一样,也是在对象撤销时进行必需的清理善后工作。析构函数不能被继承,如果需要,则要在派生类中重新定义。与基类的析构函数一样,派生类的析构函数也没有数据类型和参数。 派生类析构函数的定义的方法与基类的析构函数的定义方法完全相同,函数体只需完成对派生类新增成员的清理和善后就行了,基类和对象成员的清理善后工作系统会自动调用他们各自的析构函数来完成。,17,class A int x; public: A(int n=0) cout“构造A:“nendl; x=n; ; class B:public A int y; public: B(int m,int n):A(n) cout“构造B:“mendl; y=m; B( )cout“构造B“endl; ; void main( ) B b1(1,2), b2; ,18,class A1 int a1; ; class A2 int a2; public: A2( ) a2=0; A2(int n) a2=n; ; class B1:public A1 int b1; ;,class B2:public A2 int b2; public: B2(int m,int n):A2(n) b2 = m; B2( ) b2=1; ; void main( ) B1 obj1; /? B2 obj2; /? B2 obj3(1,2); /? ,基类里没有定义构造函数,则由系统 提供默认的构造函数,19,class A public: A(int a) cout“构造A:“ aendl; ; class B public: B(int b) cout“构造B:“ bendl; ;,class C:public A B m_b; public: C(int a,int b):A(a),m_b(b) cout“构造C“ endl; ; void main( ) C cObj(1,2); ,派生类含有子对象时,在派生类的构造函数中要给 出初始化形式,若没给出,则调用默认构造函数,20,class A int a; public: A(int a1)a=a1; ; class B:public A int b; public: B(int b1,int a1):A(a1) b=b1; ;,class C:public B int c; public: C(int c1,int b1,int a1) :B(b1,a1) c=c1; C( ) /? ; void main( ) C c(1,2,3); ,多层派生中各层的构造函数, 一般子类只向其直接父类负责,21,派生类对象析构顺序:先派生类后基类(重点),class A int x; public: A( ) cout“构造A“endl; A( ) cout“析构A“endl; ; class B:public A int y; public: B( ) cout“构造B“endl; B( ) cout“析构B“endl; ;,void main( ) A a1 B b1; ,a1,x,b1,x,y,22,class A int x; public: A(int a) x=a; cout“构造A:“xendl; A( )cout“析构:A“xendl; ; class B:public A int y; public: B(int a,int b):A(a) y=b; cout“构造B:“yendl; B( )cout“析构B:“yendl; ;,void main( ) A a1(0) B b1(1,2); B b2(3,4); ,23,class A int x; public: A(int a)x=a; cout“构造A:“ xendl; A( )cout“析构A:“ xendl; ; class B int y; public: B(int b)y=b; cout“构造B:“ yendl;,B( )cout“析构B:“ yendl; ; class C:public A B m_b; public: C(int a,int b):A(a),m_b(b) cout“构造C:“endl; C( )cout“析构C:“ endl; ; void main( )C objC(1,2);,一定弄清楚本例,24,9.4 多重继承,9.4.1 多重继承的概念 当一个派生类具有多个基类时,称这种派生为多重继承或多基派生。在多继承中,派生类拥有了所有父类成员。 多重继承声明的一般形式为: class 派生类名:派生方式1 基类名1,派生方式n 基类名n 派生类成员声明; ; 其中,冒号后面的部分称为基类表,之间用逗号分开。,25,class base1 public: int x; int a( ); int b( ); int b(int); int c( ); ; class base2 int x; int a( );,public: float b(); int c(); ; class derived:public base1, public base2 ; void main( ) derived e; e.x=10; /错误,二义性 e.a( ); /错误,二义性 e.b( ); /错误,二义性 e.c( ); /错误,二义性 ,26,多种继承中的主要问题是标识不唯一,解决办法 : 1. 使用作用域运算符 如果派生类的基类之间没有继承关系,同时又没有共同的基类,则在引用同名成员时,可在成员名前加上类名和作用域运算符“”,来区别来自不同基类的成员。 void main( ) derived e; e.base1:x=10; e.base2:a(); e.base2:b(); e.base1:c(); ,27,2. 使用同名覆盖的原则 在派生类中重新定义与基类中同名的成员(如果是成员函数,则参数表也要相同,参数不同的情况为重载)以隐蔽掉基类的同名成员,在引用这些同名的成员时,使用的就是使用派生类中的函数,也就不会出现二义性的问题了。,28,9.4.2 多重继承的构造函数和析构函数 多重继承时,也涉及到基类成员、对象成员和派生类成员的初始化问题。 声明多继承构造函数的一般形式为: 派生类名派生类名(参数总表)基类名1(参数表1),基类名n(参数表n),对象成员名1(对象成员参数表1),对象成员名m(对象成员参数表m) /派生类新增成员的初始化语句 ,29,其中: 派生类的构造函数名与派生类名相同。 参数总表列出初始化基类成员数据、新增对象成员数据和派生类新增成员数据所需要的全部参数。 冒号后列出需要使用参数进行初始化的所有基类的名字和所有对象成员的名字及各自的参数表,之间用逗号分开。对于使用缺省构造函数的基类或对象成员,可以不给出类名或对象名以及参数表。,30,class A int m_a; public: A( ) m_a=0; int GetA( )return m_a; ; class B protected: int m_b; public: B( ) m_b=1; int GetB( )return m_b; ;,class C:public A int m_c; public: C( )m_c=2; ;,31,class D:public A,protected B int m_d; public: D( )m_d=2; ; void main( ) C c; D d; coutc.GetA( )endl;/? coutd.GetA( )endl;/? coutsizeof(c)endl;/? coutsizeof(d)endl;/? coutc.GetB( )endl;/? coutd.GetB( )endl;/? ,32,m_a,m_b,m_c,m_d,GetA,GetB,m_a,GetA,m_a,m_b,GetA,GetB,public,public,protected,私有,保护,公有,不可访问,A类,B类,C类,D类,33,/找出错误代码的地方 class A int a1; protected: int a2; public: int a3; class B:protected A int b; void f1( ) a1+; public: void f2( ) a2+; protected: void f3( ) a3+; ;,class C:public B public: void ShowC( ) b+; a1+; a2+; a3+; fun1( ); fun2( ); fun3( ); ;,34,9.4.3 虚基类 1. 虚基类的概念 多继承中,要引用派生类的成员时,先是在派生类自身的作用域内寻找,若找不到,再到基类中寻找,这时,如果这些基类又有一个共同的基类,派生类访问这个公共的成员时,就有可能由于同名成员的问题而发生二义性。 2. 虚基类的定义 虚基类的声明是在派生类的声明过程中进行的,一般形式为: class 派生类名:virtual 派生方式 基类名,35,在一个类的继承过程中使用virtual修饰后,则虚基类的成员在进一步派生过程中和派生类一起维护同一个内存拷贝,避免了二义性。 3. 虚基类的构造函数和初始化 虚基类的初始化与一般的多继承的初始化在语法上是一样的,但构造函数的执行顺序不同: (1)虚基类的构造函数的执行在非虚基类的构造函数之前。 (2)在派生类的构造函数的初始化列表给出了虚基类的构造形式。,36,class base protected: int x; public: base() x=1; base(int x1) x=x1; ; class base1:virtual public base public: base1():base(2) cout“constructing base1,x=“xendl; ;,37,class base2:virtual public base public: base2() cout“constructing base2,x=“xendl; ; class derived:public base2,public base1 public: derived():base(3) cout“constrcting derived x=“xendl; ; void main() derived obj; ,38,9.5 赋值兼容,赋值兼容规则是指在需要基类对象的任何地方都可以使用公有派生类的对象来替代。通过公有继承,派生类得到了基类中除构造函数、析构函数之外的所有成员,而且所有成员的访问控制属性也和基类完全相同。公有派生类实际就具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决。 赋值兼容规则中所指的替代包括以下的情况: 派生类的对象可以赋值给基类对象。 派生类的对象可以初始化基类的引用。 派生类对象的地址可以赋给指向基类的指针。,39,class B0 public: void display( ) cout“B0:display()“endl; ; class B1:public B0 public: void display( ) cout“Bi:display()“endl; ; class D1:public B1 public: void display() cout“D1:display()“endl; ;,40,void fun1(B0 *ptr) ptr-display(); void fun2(B0 ,p= ,41,9.6 派生类的编程原则,派生类生成过程(派生类的编程步骤),吸收基类成员,改造基类成员,发展新成员,重写构造函数与析构函数,全盘接收父类成员(除构造函数与析构函数),添加和父类同名成员,即覆盖(override),添加新的与父类成员不同名的成员,42,class Shape protected: int x,y;/原始点 public: Shape() x=y=0; Shape(int a,int b) x=a; y=b; ;,43,class Rectangle:public Shape protected: int x1,y1; public: Rectangle() x1=y1=0; Rectangle(int x,int y,int x1,int y1):Shape(x,y) this-x1=x1; this-y1=y1; int GetArea() return (x1-x)*(y1-y); ;,44,class Square:public Rectangle public: Square() Square(int length) x1=

温馨提示

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

评论

0/150

提交评论