《继承性和派生性》PPT课件.ppt_第1页
《继承性和派生性》PPT课件.ppt_第2页
《继承性和派生性》PPT课件.ppt_第3页
《继承性和派生性》PPT课件.ppt_第4页
《继承性和派生性》PPT课件.ppt_第5页
已阅读5页,还剩61页未读 继续免费阅读

下载本文档

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

文档简介

第8章 继承性和派生性,8.1 基类和派生类 8.2 单继承 8.3 多继承 8.4 虚基类,8.1 基类和派生类,1、基类与派生类,基类(父类):已存在的用来派生新类的类;,派生类(子类):由已存在的类派生出的新类;,2、单继承与多继承,单继承:从一个基类派生的继承;,多继承:从多个基类派生的继承;,单继承,多继承,8.1.1 派生类的定义格式,1、单继承,class : ;,2、多继承,class : , . ;,8.1.1 派生类的定义格式(续),3、继承方式,public:公有继承;,private:私有继承;,protected:保护继承;,作用:控制基类中声明的成员在多大的范围内能被派生类的用户访问;,8.1.1 派生类的定义格式(续),8.1.2 派生类的三种继承方式,基类,继承方式: public private protected,(J),水平访问 (H),垂直访问 (V),8.1.2 派生类的三种继承方式(续),8.1.2 派生类的三种继承方式(续),私有成员不参与继承的访问控制;,说明:,基类实例(J):与继承方式无关,遵循访问控制权限的定义;,直接继承(P):可以访问基类中的公有成员和保护成员,但成员的权限随继承方式而改变;,水平访问(H)=P+J;,垂直访问(V)=P+P;,保护成员:在垂直访问(V)时相当于公有成员,在水平访问(H)时相当于私有成员;,保护继承:在垂直访问(V)时相当于公有继承,在水平访问(H)时相当于私有继承;,8.1.2 派生类的三种继承方式(续),例8.1:分析下列程序中的访问权限。,class Location public: void InitL(int xx,int yy); void Move(int xOff,int yOff); int GetX() return X; int GetY() return Y; private: int X,Y; ; void Location:InitL(int xx,int yy) X=xx; Y=yy;,8.1.2 派生类的三种继承方式(续), void Location:Move(int xOff,int yOff) X+=xOff; Y+=yOff; class Rectangle:public Location public: void InitR(int x,int y,int w,int h); int GetH() return H; int GetW() return W; private: int H,W; ; void Rectangle:InitR(int x,int y,int w,int h),公有继承,8.1.2 派生类的三种继承方式(续), InitL(x,y); W=w; H=h; #include void main() Rectangle rect; rect.InitR(2,3,20,10); rect.Move(3,2); coutrect.GetX()“, “rect.GetY()“, “ rect.GetH()“, “rect.GetW()endl; ,水平访问,输出: 5,5,10,20,8.1.2 派生类的三种继承方式(续),/派生类 class V:public Rectangle public: void Function(); ; void V:Function() Move(3,2); ,公有继承,垂直访问,正确,若继承方式为private, Move(3,2)是否正确?为什么?,若继承方式为private,Move(3,2)仍然正确。 原因:由于类Rectangle对类Location是公有继承,而类V对类Rectangle是直接继承,直接继承时不考虑继承方式,因此在类V内可以访问基类Location的公有成员;,8.1.2 派生类的三种继承方式(续),class Rectangle:private Location public: void InitR(int x,int y,int w,int h); int GetH() return H; int GetW() return W; private: int W,H; ; void Rectangle:InitR(int x,int y,int w,int h) InitL(x,y); W=w; H=h; ,私有继承,直接继承,正确,8.1.2 派生类的三种继承方式(续),#include void main() Rectangle rect; rect.InitR(2,3,20,10); rect.Move(3,2); coutrect.GetX()“, “rect.GetY()“, “ rect.GetH()“, “rect.GetW()endl; ,水平访问,/修改 class Rectangle:private Location public: void InitR(int x,int y,int w,int h); void Move(int xOff,int yOff),8.1.2 派生类的三种继承方式(续), Location:Move(xOff,yOff); int GetX() return Location:GetX(); int GetY() return Location:GetY(); int GetH() return H; int GetW() return W; private: int W,H; ; void Rectangle:InitR(int x,int y,int w,int h) InitL(x,y); W=w; H=h; ,通过成员名限定符(:) 指明调用基类中的成员,8.1.2 派生类的三种继承方式(续),class V:public Rectangle public: void Function(); ; void V:Function() Move(3,2); ,公有继承,垂直访问,错误,若继承方式为private, Move(3,2)是否正确?为什么?,若继承方式为private,Move(3,2)仍然错误。 原因:由于类Rectangle对类Location是私有继承,而类V对类Rectangle是直接继承,直接继承时不考虑继承方式,因此在类V内不可以访问基类Location的公有成员;,8.1.2 派生类的三种继承方式(续),class A protected: int X; ; void main() A a; a.X=5; ,class B:public A public: void Function(); ; void B:Function() X=5; ,错误,水平访问时 保护成员相当于 私有成员,正确,垂直访问时 保护成员相当于 公有成员,8.1.3 基类与派生类的关系,基类是对若干个派生类的抽象,而派生类是基类的具体化;基类抽取了它的派生类的公共特征,而派生类通过增加行为将抽象类变为某种有用的类型。,1、派生类是基类的具体化,2、派生类是基类定义的延续,派生类将其自身与基类区别开来的方法是添加数据成员和成员函数;,3、派生类是基类的组合,8.2.1 成员访问权限的控制,例8.2:分析下列程序中的访问权限,并回答问题。,#include class A public: void f1(); protected: int j1; private: int i1; ; class B:public A public: void f2();,8.2.1 成员访问权限的控制(续),protected: int j2; private: int i2; ; class C:public B public: void f3(); ;,回答下列问题,并说明原因。,1、派生类B中成员函数f2()能否访问基类A中的成员:f1()、j1和i1?,8.2.1 成员访问权限的控制(续),2、派生类B的对象b1能否访问基类A中的成员:f1()、j1和i1?,可以访问f1()和j1,不可以访问i1; 原因:类B对类A是直接继承,可以访问A中的公有成员和保护成员,而不可以访问私有成员;,可以访问f1(),不可以访问j1和i1; 原因:类B的对象b1对类A中的成员是水平访问,可以访问A中的公有成员,而不可以访问保护成员和私有成员;,3、派生类C中的成员函数f3()能否访问直接基类B中的成员:f2()、j2和i2?能否访问间接基类A中的成员: f1()、j1和i1?,8.2.1 成员访问权限的控制(续),4、派生类C的对象c1能否访问直接基类B中的成员:f2()、j2和i2?能否访问间接基类A中的成员: f1()、j1和i1?,可以访问直接基类中的f2()和j2以及间接基类中的f1()和j1,不可以访问i2和i1; 原因:类C对类B是直接继承,原因同1;类C对类A是垂直访问,可以访问A中的公有成员和保护成员,而不可以访问私有成员;,可以访问直接基类中的f2()以及间接基类中的f1(),其他都不可以访问; 原因:类C的对象c1对B中的成员是水平访问,原因同2;c1对A的访问,相当于先直接继承后水平访问;,5、如将上述两处继承方式由public改为private,试回答上述问题。,8.2.1 成员访问权限的控制(续),例8.3:分析下列程序,并回答问题。,#include class A public: void f(int i) coutiendl; void g() cout“g“endl; ; class B:A public: void h() cout“h“endl; A:f; ;,缺省继承方式 为private,将基类中的成员 说明为派生类中 的成员,8.2.1 成员访问权限的控制(续),void main() B d1; d1.f(6); d1.g(); d1.h(); ,回答下列问题,并说明原因。,1、执行该程序时,哪个语句会出现编译错?,2、去掉出错语句后,执行结果是什么?,3、类B从类A继承时的缺省继承方式是什么?,4、派生类B中,A:f的含义是什么?,5、将B的继承方式改为public,输出结果是什么?,编译错。 B以私有继承 方式继承A, 因此B的对象 b1不能访问A 的成员函数,输出(2): 6 h,输出(5): 6 g h,8.2.2 构造函数和析构函数,1、派生类构造函数,基类子对象:派生类的对象中由基类中说明的数据成员和操作所构成的封装体;,基类子对象由基类中的构造函数进行初始化;,构造函数不能被继承;,派生类构造函数的工作:,对自己的数据成员进行初始化;,负责调用基类构造函数使基类的数据成员得以初始化;,调用子对象的构造函数,对派生类中的子对象进行初始化;,注意与基类的子对象的区别,必须在成员 初始化列表 中进行,8.2.2 构造函数和析构函数(续),派生类构造函数格式:,若某项的参数表为空,则该项可从成员初始化列表中省略,表示使用缺省构造函数初始化该基类子对象;,() :(), () ,说明:,8.2.2 构造函数和析构函数(续),派生类构造函数调用顺序:,基类的构造函数;,子对象的构造函数;,派生类构造函数体;,8.2.2 构造函数和析构函数(续),例8.4:分析下列程序的输出结果。,#include class B public: B(); B(int i); B(); void Print() const; private: int b; ; B:B() b=0; cout“Bs default constructor called. “endl;,8.2.2 构造函数和析构函数(续), B:B(int i) b=i; cout“Bs constructor called. “endl; B:B() cout“Bs destructor called. “endl; void B:Print() const coutbendl; class C:public B ,8.2.2 构造函数和析构函数(续),public: C(); C(int i,int j); C(); void Print() const; private: int c; ; C:C() c=0; cout“Cs default constructor called. “endl; C:C(int i,int j):B(i) c=j;,8.2.2 构造函数和析构函数(续),cout“Cs constructor called. “endl; C:C() cout“Cs destructor called. “endl; void C:Print() const B:Print(); coutcendl; void main() C obj(5,6); obj.Print(); ,输出: Bs constructor called. Cs constructor called. 5 6 Cs destructor called. Bs destructor called.,8.2.2 构造函数和析构函数(续),2、派生类析构函数,执行派生类的析构函数时,基类的析构函数也将被调用;,析构函数不能被继承;,析构函数的执行顺序与构造函数严格相反;,派生类的析构函数;,基类的析构函数;,8.2.2 构造函数和析构函数(续),例8.5:分析下列程序的输出结果。,#include class M public: M(); M(int i,int j); M(); void Print(); private: int m1,m2; ; M:M() m1=m2=0; ,Print()函数是否可以 定义为常成员函数?,8.2.2 构造函数和析构函数(续),M:M(int i,int j) m1=i; m2=j; cout“Ms constructor called. “m1“, “ m2endl; M:M() cout“Ms destructor called. “m1“, “ m2endl; void M:Print() coutm1“, “m2“, “; ,8.2.2 构造函数和析构函数(续),class N:public M public: N() n=0; N(int i,int j,int k); N(); void Print(); private: int n; ; M:M(int i,int j,int k):M(i,j),n(k) cout“Ns costructor called. “nendl; N:N() ,8.2.2 构造函数和析构函数(续),cout“Ns destructor called. “nendl; void N:Print() M:Print(); coutnendl; void main() N n1(5,6,7), n2(-2,-3,-4); n1.Print(); n2.Print(); ,输出: Ms constructor called.5,6 Ns constructor called.7 Ms constructor called.-2,-3 Ns constructor called.-4 5,6,7 -2,-3,-4 Ns destructor called.-4 Ms destructor called.-2,-3 Ns destructor called.7 Ms destructor called.5,6,8.2.2 构造函数和析构函数(续),3、派生类构造函数使用中应注意的问题,派生类构造函数的定义中可以省略对基类构造函数的调用,其条件是在基类中必须有缺省的构造函数或者根本没有定义任何构造函数;,当基类的构造函数使用一个或多个参数时,派生类必须定义构造函数,提供将参数传递给基类构造函数的途径;,编译器自动生成缺省构造函数,设基类数据成员为m个,派生类数据成员为n个, 派生类的参数个数为x,则:0=x=m+n;,8.2.2 构造函数和析构函数(续),例8.6:分析下列程序的输出结果。,#include class A public: A() a=0; A(int i) a=i; void Print() couta“, “; private: int a; ; class B:public A public: B() b1=b2=0; B(int i) b1=i;b2=0;,8.2.2 构造函数和析构函数(续),B(int i,int j,int k):A(i),b1(j),b2(k) void Print() A:Print(); coutb1“, “b2endl; private: int b1,b2; ; void main() B d1,d2(5),d3(4,5,6); d1.Print(); d2.Print(); d3.Print(); ,输出: 0,0,0 0,5,0 4,5,6,8.3.1 多继承的概念,class : , ;,8.3.2 多继承的构造函数,() :(), () (), . ,多继承构造函数格式:,8.3.2 多继承的构造函数(续),派生类构造函数负责所有基类构造函数的调用;,派生类构造函数执行顺序:,执行所有基类的构造函数;,执行所有子对象的构造函数;,执行派生类构造函数体;,处于同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的各基类顺序,与派生类构造函数中所定义的成员初始化列表中的各项顺序无关;,8.3.2 多继承的构造函数(续),例8.7:分析下列程序的输出结果。,#include class B1 public: B1(int i) b1=i; cout“Constructor B1. “endl; void Print() coutb1endl; private: int b1; ; class B2 public: B2(int i) b2=i; cout“Constructor B2. “endl; void Print() coutb2endl;,8.3.2 多继承的构造函数(续),private: int b2; ; class B3 public: B3(int i) b3=i; cout“Constructor B3. “endl; int Getb3() return b3; private: int b3; ; class A:public B2,public B1 public: A(int i,int j,int k,int l);,多继承,8.3.2 多继承的构造函数(续),void Print(); private: int a; B3 bb; ; A:A(int i,int j,int k,int l):B1(i),B2(j),bb(k) a=l; cout“Constructor A. “endl; void A:Print() B1:Print(); B2:Print(); coutabb.Getb3()endl;,子对象,基类构造函数调用顺序 与定义时的顺序不同,8.3.2 多继承的构造函数(续), void main() A aa(1,2,3,4); aa.Print(); ,输 出,Constructor B2.2 Constructor B1.1 Constructor B3.3 Constructor A.4 1 2 4,3,8.3.3 二义性问题,1、产生二义性的原因,在多继承情况下,造成的对基类中某个成员的访问出现的不唯一的情况;,class A class C:public A,public B public: public: void f(); void g(); ; void h(); class B ; public: void f(); void g(); ;,8.3.3 二义性问题(续),问题:若定义C c1;,则c1.f()是否正确?,答:c1.f()将产生二义性;,原因:不能识别是调用类A或类B的f函数;,解决方法: a.区别出是类A或类B的f函数; c1.A:f(); 或 c1.B:f(); b.在类中定义同名函数f;,当一个派生类从多个基类派生,而这些基类又有一个共同的基类,则对该基类中说明的成员进行访问时,可能会出现二义性;,8.3.3 二义性问题(续),class A class B2:public A public: private: int a; int b2; ; ; class B1:public A class C:public B1,public B2 private: public: int b1; int f(); ; private: int c; ;,8.3.3 二义性问题(续),问题:若定义C c1;,则c1.a与c1.A:a是否正确?,答:c1.a与c1.A:a将产生二义性;,原因:不能识别是通过类B1或类B2调用类A的a;,解决方法: a.区别出是通过类B1或类B2调用类A的a; c1.B1:a; 或 c1.B2:a; b.虚基类;,2、解决方法,利用成员名限定法消除二义性;,在类中定义一个同名成员;,虚基类;,8.3.3 二义性问题(续),3、支配规则(定义同名成员方法),支配规则:类X中的名字N支配类Y中同名的名字N是指类X以类Y为它的一个基类;,如果一个名字支配另外一个名字,则二者之间不存在二义性。当选择该名字时,使用支配者的名字;,4、说明,一个类不能从同一个类中直接继承一次以上;,二义性检查在访问控制和类型检查之前进行,访问控制和类型检查不能解决二义性问题;,8.3.3 二义性问题(续),class A public: void fun(); ; class B private: void fun(); ; class C:public A,public B ; void main() C obj; obj.fun(); ,obj.fun()产生二义性,8.3.3 二义性问题(续),例8.8:分析下列程序的输出结果。,#include class A public: A(int i) a=i; cout“Constructor A. “iendl; A() cout“Destructor A. “endl; void Print() coutaendl; private: int a; ; class B1:public A public: B1(int i,int j):A(i) b1=j;,8.3.3 二义性问题(续),cout“Constructor B1. “endl; B1() cout“Destructor B1. “endl; void Print() A:Print(); coutb1endl; private: int b1; ; class B2:public A public: B2(int i,int j):A(i) b2=j; cout“Constructor B2. “endl; B2() cout“Destructor B2. “endl; void Print() A:Print();coutb2endl; private: int b2; ;,8.3.3 二义性问题(续),class C:public B1,public B2 C(int i,int j,int k,int l,int m):B1(i,j),B2(k,l),c(m) cout“Constructor C. “endl; C() cout“Destructor C. “endl; void Print() B1:Print(); B2:Print(); coutcendl; private: int c; ; void main() C c1(1,2,3,4,5); c1.Print(); ,8.3.3 二义性问题(续),Constructor A. Constructor B1. Constructor A. Constructor B2. Constructor C. 1 2 3 4 5 Destructor C. Destructor B2. Destructor A. Destructor B1. Destructor A.,执 行 结 果,注意基类A的实例的数目,如果a是类A的公有成员, obj.a是否正确?,8.4.1 虚基类的引入和说明,引入目的:解决二义性问题;,格式:,virtual ,说明:,关键字virtual与关键字public或private的相对位置无关,但必须位于虚基类名之前,且virtual只对紧随其后的基类名起作用;,例如: class D:virtual public A,private B,virutal public C 其中:类A和类C是虚基类,而类B是非虚基类;,8.4.1 虚基类的引入和说明(续),class A public: void f(); protected: int a; ; class B:virtual public A protected: int b; ; class C:virtual public B protected: int c;,虚基类,虚基类,8.4.1 虚基类的引入和说明(续),; class D:public B

温馨提示

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

评论

0/150

提交评论