继承性和派生性_第1页
继承性和派生性_第2页
继承性和派生性_第3页
继承性和派生性_第4页
继承性和派生性_第5页
已阅读5页,还剩61页未读 继续免费阅读

下载本文档

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

文档简介

1、第8章继承性和派生性8.1基类和派生类1、基类与派生类 基类(父类):已存在的用来派生新类的类; 派生类(子类):由已存在的类派生出的新类;2、单继承与多继承 单继承:从一个基类派生的继承; 多继承:从多个基类派生的继承;基类派生类abacb单继承多继承8.1.1派生类的定义格式1、单继承class : ;2、多继承class : , .;8.1.1派生类的定义格式(续)3、继承方式 public:公有继承; private:私有继承; protected:保护继承; 作用:控制基类中声明的成员在多大的范围内能被派生类的用户访问;私有成员公有成员保护成员私有成员公有成员保护成员基类部分新定义部

2、分派生类派生类成员派生类的构成8.1.1派生类的定义格式(续)8.1.2派生类的三种继承方式基类派生类派生类基类实例派生类实例继承方式:publicprivateprotected(j)水平访问(h)垂直访问(v)直接继承(p)8.1.2派生类的三种继承方式(续)表:继承对基类成员的访问能力公公有有继继承承私私有有继继承承保保护护继继承承jph vjph vjph v私私有有成成员员 公公有有成成员员 保保护护成成员员 (私)(私)(保)8.1.2派生类的三种继承方式(续)私有成员不参与继承的访问控制;说明:基类实例(j):与继承方式无关,遵循访问控制权限的定义;直接继承(p):可以访问基类中

3、的公有成员和保护成员,但成员的权限随继承方式而改变;水平访问(h)=p+j;垂直访问(v)=p+p;保护成员:在垂直访问(v)时相当于公有成员,在水平访问(h)时相当于私有成员;保护继承:在垂直访问(v)时相当于公有继承,在水平访问(h)时相当于私有继承;8.1.2派生类的三种继承方式(续)例8.1:分析下列程序中的访问权限。class locationpublic: void initl(int xx,int yy); void move(int xoff,int yoff); int getx() return x; int gety() return y;private: int x,y

4、;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 locationpublic: 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)公

5、有继承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,208.1.2派生类的三种继承方式(续)/派生类class v:public rectanglepublic: void function();void v:function() move(3,2);公有继承垂直访

6、问,正确若继承方式为private,move(3,2)是否正确?为什么?若继承方式为private,move(3,2)仍然正确。原因:由于类rectangle对类location是公有继承,而类v对类rectangle是直接继承,直接继承时不考虑继承方式,因此在类v内可以访问基类location的公有成员;8.1.2派生类的三种继承方式(续)class rectangle:private locationpublic: void initr(int x,int y,int w,int h); int geth() return h; int getw() return w;private: i

7、nt 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 locationpublic: void initr(in

8、t 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;通过成员名限定符

9、(:)指明调用基类中的成员8.1.2派生类的三种继承方式(续)class v:public rectanglepublic: 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 aprotec

10、ted: int x;void main() a a; a.x=5;class b:public apublic: void function();void b:function() x=5;错误,水平访问时保护成员相当于私有成员正确,垂直访问时保护成员相当于公有成员8.1.3基类与派生类的关系基类是对若干个派生类的抽象,而派生类是基类的具体化;基类抽取了它的派生类的公共特征,而派生类通过增加行为将抽象类变为某种有用的类型。1、派生类是基类的具体化2、派生类是基类定义的延续派生类将其自身与基类区别开来的方法是添加数据成员和成员函数;3、派生类是基类的组合8.2.1成员访问权限的控制例8.2:分

11、析下列程序中的访问权限,并回答问题。#include class apublic: void f1();protected: int j1;private: int i1;class b:public apublic: void f2();8.2.1成员访问权限的控制(续)protected: int j2;private: int i2;class c:public bpublic: void f3();回答下列问题,并说明原因。1、派生类b中成员函数f2()能否访问基类a中的成员:f1()、j1和i1?8.2.1成员访问权限的控制(续)2、派生类b的对象b1能否访问基类a中的成员:f1()

12、、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()

13、和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 apublic: void f(int i) coutiendl; void g

14、() coutgendl;class b:apublic: void h() couthendl; 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):

15、 6 h输出(5): 6 g h8.2.2构造函数和析构函数1、派生类构造函数 基类子对象:派生类的对象中由基类中说明的数据成员和操作所构成的封装体; 基类子对象由基类中的构造函数进行初始化; 构造函数不能被继承; 派生类构造函数的工作:k对自己的数据成员进行初始化;k负责调用基类构造函数使基类的数据成员得以初始化;k调用子对象的构造函数,对派生类中的子对象进行初始化;注意与基类的子对象的区别必须在成员初始化列表中进行8.2.2构造函数和析构函数(续) 派生类构造函数格式:若某项的参数表为空,则该项可从成员初始化列表中省略,表示使用缺省构造函数初始化该基类子对象;():(), ()说明:8.2

16、.2构造函数和析构函数(续) 派生类构造函数调用顺序:k基类的构造函数;k子对象的构造函数;k派生类构造函数体;8.2.2构造函数和析构函数(续)例8.4:分析下列程序的输出结果。#include class bpublic: b(); b(int i); b(); void print() const;private: int b;b:b() b=0; coutbs default constructor called. endl;8.2.2构造函数和析构函数(续)b:b(int i) b=i; coutbs constructor called. endl; b:b() coutbs de

17、structor called. endl;void b:print() const coutbendl;class c:public b8.2.2构造函数和析构函数(续)public: c(); c(int i,int j); c(); void print() const; private: int c;c:c() c=0; coutcs default constructor called. endl;c:c(int i,int j):b(i) c=j;8.2.2构造函数和析构函数(续) coutcs constructor called. endl;c:c() coutcs destr

18、uctor called. endl;void c:print() const b:print(); coutcendl;void main() c obj(5,6); obj.print();输出:bs constructor called.cs constructor called.56cs destructor called.bs destructor called.8.2.2构造函数和析构函数(续)2、派生类析构函数 执行派生类的析构函数时,基类的析构函数也将被调用; 析构函数不能被继承; 析构函数的执行顺序与构造函数严格相反;k派生类的析构函数;k基类的析构函数;8.2.2构造函数和

19、析构函数(续)例8.5:分析下列程序的输出结果。#include class mpublic: 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; coutms constructor called. m1, m2endl;m:m() coutms destructor called. m1, m2endl;void m:print() coutm1, m2, ;8.2

20、.2构造函数和析构函数(续)class n:public mpublic: 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) coutns costructor called. nendl;n:n()8.2.2构造函数和析构函数(续) coutns destructor called. nendl;void n:print() m:print(); coutnendl;void main() n n1(5,6,7), n2(-2,-3,-4); n

21、1.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,68.2.2构造函数和析构函数(续)3、派生类构造函数使用中应注意的问题 派生类构造函数的定义中可以省略对基类构造函数

22、的调用,其条件是在基类中必须有缺省的构造函数或者根本没有定义任何构造函数; 当基类的构造函数使用一个或多个参数时,派生类必须定义构造函数,提供将参数传递给基类构造函数的途径;编译器自动生成缺省构造函数设基类数据成员为m个,派生类数据成员为n个,派生类的参数个数为x,则:0=x=m+n;8.2.2构造函数和析构函数(续)例8.6:分析下列程序的输出结果。#include class apublic: a() a=0; a(int i) a=i; void print() couta, ;private: int a;class b:public apublic: b() b1=b2=0; b(i

23、nt 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,00,5,04,5,68.3.1多继承的概念class : , ;8.3.2多继承的构造函数():(), () (),. 多继承构造函数格式:8.3.2多继承的构造函数(续) 派生类构造

24、函数负责所有基类构造函数的调用; 派生类构造函数执行顺序:k执行所有基类的构造函数;k执行所有子对象的构造函数;k执行派生类构造函数体; 处于同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的各基类顺序,与派生类构造函数中所定义的成员初始化列表中的各项顺序无关;8.3.2多继承的构造函数(续)例8.7:分析下列程序的输出结果。#include class b1public: b1(int i) b1=i; coutconstructor b1. endl; void print() coutb1endl;private: int b1;class b2public: b2(int i

25、) b2=i; coutconstructor b2. endl; void print() coutb2endl;8.3.2多继承的构造函数(续)private: int b2;class b3public: b3(int i) b3=i; coutconstructor b3. endl; int getb3() return b3;private: int b3;class a:public b2,public b1public: a(int i,int j,int k,int l);多继承8.3.2多继承的构造函数(续) void print();private: int a; b3

26、bb;a:a(int i,int j,int k,int l):b1(i),b2(j),bb(k) a=l; coutconstructor 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.2constructor b1.1constructor b3.3constructor a.4124,38.3.3二义性问题1、产生二

27、义性的原因 在多继承情况下,造成的对基类中某个成员的访问出现的不唯一的情况;class aclass c:public a,public b public: public: void f(); void g(); void h();class b ;public: void f(); void g();void f();c1.f()a.f()b.f()c8.3.3二义性问题(续)问题:若定义c c1;,则c1.f()是否正确?答:c1.f()将产生二义性;原因:不能识别是调用类a或类b的f函数;解决方法:a.区别出是类a或类b的f函数;c1.a:f();或c1.b:f();b.在类中定义同名函

28、数f; 当一个派生类从多个基类派生,而这些基类又有一个共同的基类,则对该基类中说明的成员进行访问时,可能会出现二义性;8.3.3二义性问题(续)class aclass b2:public a public: private: int a; int b2; ;class b1:public aclass c:public b1,public b2 private: public: int b1; int f(); private: int c; ;c1.aa.ab1.b1cb2.b2a.a8.3.3二义性问题(续)问题:若定义c c1;,则c1.a与c1.a:a是否正确?答:c1.a与c1.a

29、: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、说明 一个类不能从同一个类中直接继承一次以上; 二义性检查在访问控制和类型检查之前进行,访问控制和类型检查不能解决二义性问题;

30、8.3.3二义性问题(续)class apublic: void fun();class bprivate: void fun();class c:public a,public b;void main() c obj; obj.fun();obj.fun()产生二义性8.3.3二义性问题(续)例8.8:分析下列程序的输出结果。#include class apublic: a(int i) a=i; coutconstructor a. iendl; a() coutdestructor a. endl; void print() coutaendl;private: int a;class

31、 b1:public apublic: b1(int i,int j):a(i) b1=j; 8.3.3二义性问题(续) coutconstructor b1. endl; b1() coutdestructor b1. endl; void print() a:print(); coutb1endl; private: int b1;class b2:public apublic: b2(int i,int j):a(i) b2=j; coutconstructor b2. endl; b2() coutdestructor b2. endl; void print() a:print();

32、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) coutconstructor c. endl; c() coutdestructor c. endl; void print() b1:print(); b2:print(); coutcendl; private: int c;void main() c c1(1,2,3,4,5); c1.print();a1.ab1.b1c1.cb2.b2a2.

33、a8.3.3二义性问题(续)constructor a.constructor b1. constructor a.constructor b2.constructor c.12345destructor c.destructor b2.destructor a.destructor b1.destructor a.执行结果注意基类a的实例的数目如果a是类a的公有成员,obj.a是否正确?8.4.1虚基类的引入和说明 引入目的:解决二义性问题; 格式:virtual 说明:关键字virtual与关键字public或private的相对位置无关,但必须位于虚基类名之前,且virtual只对紧随其

34、后的基类名起作用;例如:class d:virtual public a,private b,virutal public c其中:类a和类c是虚基类,而类b是非虚基类;8.4.1虚基类的引入和说明(续)class apublic: void f();protected: int a;class b:virtual public aprotected: int b;class c:virtual public bprotected: int c;虚基类虚基类8.4.1虚基类的引入和说明(续);class d:public b,public cpublic: int g();private: int d;下列各语句是否正确?d n;n.f();void d:g() f();bd.g()ca.f()n.f()正

温馨提示

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

评论

0/150

提交评论