第04章继承性与多态性

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

第4章继承性与多态性4.1继承性与派生4.1.1继承的概念所谓继承(inheritance)就是利用已有的数据类型定义出新的数据类型。在继承关系中,被继承的类称为基类(baseclass)或父类,而通过继承关系定义出来的新类则被称为派生类(derivedclass)或子类。派生类既可以对基类的性质进行扩展又可以对基类进行限制,从而得到更加灵活、适用的可重用模块,大大缩短了程序的开发时间。一个派生类既可以从一个基类派生也可以从多个基类派生。从一个基类派生称为单继承;从多个基类派生称为多重继承。1.单继承单继承的定义形式如下:class派生类名:访问方式基类名{派生类中的新成员};其中,派生类名是新定义的类名。基类名必须是程序中已有的一个类。在单继承中,每个类可以有多个派生类,但是每个派生类只能有一个基类。例如:classA{...};classB:publicA{...};2.多重继承所谓多重继承是指派生类从多个基类中派生而来的。定义多重继承类的方式如下:class派生类名:访问方式1基类名1,访问方式2基类名2……{派生类中的新成员};例如:classA{...第4章继承性与多态性·21·};classB{...};classC:publicA,publicB{...};从定义格式上来看,多重继承与单继承的区别主要是多重继承的基类多于一个。3.访问方式不管在单继承还是在多重继承的定义格式中,访问方式,即继承方式,可以为public、private或protected,如果省略,则默认为private方式。访问方式为public方式时,这种继承称为公有继承;访问方式为private方式时,这种继承称为私有继承;访问方式为protected方式时,这种继承称为保护继承。4.1.2派生类的生成过程在给出了派生类的定义和相应成员函数的实现代码后,整个派生类的定义就算完成了,这是就可以利用该类定义相应的对象处理实际问题了。由于派生类是在基类的基础上经过继承而产生的,所以搞清派生类中到底有哪些成员对于更好的使用派生类是很重要的。事实上,派生新类经历了三个步骤:1.吸收基类成员派生类继承吸收了基类的全部数据成员以及除了构造函数、析构函数之外的全部函数成员。也就是说,基类中的构造函数和析构函数不能继承到派生类中的。2.改造基类成员对继承到派生类中基类成员的改造包括两个方面:一是基类成员的访问方式问题,这由派生类定义时的访问方式来控制;二是对基类数据成员或成员函数的覆盖,也就是在派生类中定义了与基类中同名的数据成员或函数成员,由于作用域不同,于是发生同名覆盖,基类中的成员就被替换成派生类中的同名成员。3.添加新成员在派生类中,除了从基类中继承过来的成员外,还可以根据需要在派生类中添加新的数据成员和成员函数,以此实现必要的新功能。可以看出,在派生类中可以添加新成员的机制是继承和派生机制的核心,保证了派生类在功能上比基类有所发展。4.1.3继承方式对基类成员的访问控制前面已经分析,派生类继承和吸收了基类的全部数据成员和除了构造函数、析构函数之外的全部函数成员,但这些成员在派生类中的访问属性是可以调整的,这是由派生类定义格式中的继承方式来决定的,也就是继承方式控制了基类中具有不同访问属性的成员在派生类中的访问属性。由于继承方式可以有public、private和protected三种,不同的继承方式会导致原来具有不同访问属性的基类成员在派生类中的访问属性也有所不同。这种访问包括两个方面:一是派生类中新增成员对从基类继承来的成员的访问;二是派生类的外部通过派生类的对象从基类继承来的成员的访问。1.公有继承当类的继承方式为公有继承时,基类中public和protected成员的访问属性在派生·22·第4章继承性与多态性类中不变,而基类private成员不可访问。也就是说,基类的public和protected成员在公有继承方式下分别继承为派生类的public和protected成员,派生类中的其他成员可以直接访问它们,在派生类的外部只能通过派生类的对象访问从基类继承来的public成员。而无论是派生类的成员还是派生类的对象都无法访问从基类继承来的private成员。2.私有继承当类的继承方式为私有继承时,基类中的public和protected成员都以private成员出现在派生类中,而基类private成员不可访问。也就是说,基类的public和protected成员在私有继承方式下被继承为派生类的private成员,派生类中的其他成员可以直接访问它们,但在派生类的外部无法通过派生类的对象访问它们。而无论是派生类的成员还是派生类的对象都无法访问从基类继承来的private成员。可以看出,经过私有继承后,所有基类的成员都成为派生类的私有成员,如果进一步派生的话,基类的成员就无法在新的派生类中被访问。因此,经过私有继承后,基类的成员再也无法在以后的派生类中发挥作用,实际是相当于中止了基类功能的继续派生。3.保护方式当类的继承方式为保护继承时,基类中的public和protected成员都以protected成员出现在派生类中,而基类private成员不可访问。也就是说,基类的public和protected成员在保护继承方式下被继承为派生类的protected成员,派生类中的其他成员可以直接访问它们,但在派生类的外部无法通过派生类的对象访问它们。而无论是派生类的成员还是派生类的对象都无法访问从基类继承来的private成员。继承访问方式基类成员特性派生类成员特性公有publicpublicprotectedprivatepublicprotected不可访问私有privatepublicprotectedprivateprivateprivate不可访问保护protectedpublicprotectedprivateprotectedprotected不可访问示例:#includeiostream.hclassA{public:voidf1();protected:intj1;private:inti1;};classB:publicAclassB{public:voidf2();voidf1();第4章继承性与多态性·23·{public:voidf2();protected:intj2;private:inti2;};classC:publicB{public:voidf3();};classC:publicB{public:voidf3();voidf1();voidf2();protected:intj1,j2;};回答如下问题:⑴B的成员函数f2()能否访问A中的f1()、i1、j1等成员?⑵B的对象b1能否访问A中的f1()、i1、j1等成员?⑶C的成员函数f3()能否访问B中的f2()、j2等成员?能否访问A中的f1()、i1、j1等成员?⑷C的对象能否访问B中的f2()、i2、j2等成员?能否访问A中的f1()、i1、j1等成员?⑸从上述过程可得出对公有访问继承什么样的结论?解答:⑴B的成员函数f2()能访问A中的f1()、j1,不能访问i1。⑵B的对象b1能访问A中的f1(),不能访问i1、j1。⑶C的成员函数f3()能访问B中的f2()、j2,不能访问i2。能访问A中的f1()、j1,不能访问i1。⑷C的对象能否访问B中的f2()和A中的f1(),其他均不可访问。⑸在公有继承时,派生类的成员函数可以访问基类中的公有成员和保护成员;派生类的对象仅可访问基类中的公有成员。示例:#includeiostream.hclassA{public:voidf(inti){coutiendl;·24·第4章继承性与多态性}voidg(){coutgendl;}};classB:A{public:voidh(){couth\n;}A::f;};voidmain(){Bd1;d1.f(6);//d1.g();d1.h();}运行结果:6h示例:#includeiostream.h#includestring.hclassA{public:A(constchar*nm){strcpy(name,nm);}//private:protected:charname[80];};classB:publicA{public:B(constchar*nm):A(nm){}voidPrintName()const;};voidB::PrintName()const{第4章继承性与多态性·25·coutname:nameendl;}voidmain(){Bb1(WangLi);b1.PrintName();}4.1.4派生类的构造函数和析构函数继承和派生的机制可以使派生类继承基类的成员,从而实现了原有代码的重用,但是,由于基类的构造函数和析构函数不能继承,那么在派生类中,如果对派生类新增的成员进行初始化,就必须在派生类中根据需要加入新的构造函数,如果对从基类继承下来的成员进行初始化,还必须由基类的构造函数来完成,所以需要在派生类中的构造函数,一方面负责调用基类的构造函数对基类成员进行初始化,另一方面还要负责对基类的构造函数所需要的参数进行必要的设置。1.单继承方式下派生类构造函数的定义在单继承方式下,派生类的构造函数的定义格式如下:派生类名::派生类构造函数名(形参表):基类构造函数名(参数表),子对象名(参数表)...{//派生类构造函数的函数体};在此定义格式中,派生类构造函数名后面括号内的参数表中包括参数的类型和参数名,而基类构造函数名后面括号内的参数表中只有参数名而没有参数类型,并且这些参数必须是来源于派生类构造函数名后面括号内的参数。示例:#includeiostream.hclassA{private:inta;public:A(){a=0;coutA'sdefaultconstructorcalled.endl;}A(inti){a=i;coutA'sconstructorcalled.endl;}~A(){coutA'sdestructorcalled.endl;}voidPrint()const{couta,;}intGeta(){returna;}};classB:publicA{private:intb;Aaa;public:B(){b=0;coutB'sdefaultconstructorcalled.endl;}·26·第4章继承性与多态性B(inti,intj,intk);~B(){coutB'sdestructorcalled.endl;}voidPrint();};B::B(inti,intj,intk):A(i),aa(j){b=k;coutB'sconstructorcalled.endl;}voidB::Print(){A::Print();coutb,aa.Geta()endl;}voidmain(){Bbb[2];bb[0]=B(1,2,5);bb[1]=B(3,4,7);for(inti=0;i2;i++)bb[i].Print();}运行结果:A'sdefaultconstructorcalled.A'sdefaultconstructorcalled.B'sdefaultconstructorcalled.A'sdefaultconstructorcalled.A'sdefaultconstructorcalled.B'sdefaultconstructorcalled.A'sconstructorcalled.A'sconstructorcalled.B'sconstructorcalled.B'sdestructorcalled.A'sdestructorcalled.A'sdestructorcalled.A'sconstructorcalled.A'sconstructorcalled.B'

1 / 23
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功