第04章 继承性与多态性

上传人:gp****x 文档编号:142974863 上传时间:2022-08-25 格式:DOC 页数:24 大小:77KB
收藏 版权申诉 举报 下载
第04章 继承性与多态性_第1页
第1页 / 共24页
第04章 继承性与多态性_第2页
第2页 / 共24页
第04章 继承性与多态性_第3页
第3页 / 共24页
资源描述:

《第04章 继承性与多态性》由会员分享,可在线阅读,更多相关《第04章 继承性与多态性(24页珍藏版)》请在装配图网上搜索。

1、第4章 继承性与多态性.1 继承性与派生41。1继承的概念所谓继承(inheritance)就是利用已有的数据类型定义出新的数据类型。在继承关系中,被继承的类称为基类(ase class)或父类,而通过继承关系定义出来的新类则被称为派生类(derid clas)或子类.派生类既可以对基类的性质进行扩展又可以对基类进行限制,从而得到更加灵活、适用的可重用模块,大大缩短了程序的开发时间。一个派生类既可以从一个基类派生也可以从多个基类派生。从一个基类派生称为单继承;从多个基类派生称为多重继承。1单继承单继承的定义形式如下:cass 派生类名:访问方式基类名派生类中的新成员;其中,派生类名是新定义的类

2、名。基类名必须是程序中已有的一个类。在单继承中,每个类可以有多个派生类,但是每个派生类只能有一个基类。例如:clas。.。;clasB:publiA。.;2.多重继承所谓多重继承是指派生类从多个基类中派生而来的。定义多重继承类的方式如下:clas 派生类名:访问方式1 基类名1,访问方式2 基类名2派生类中的新成员;例如:cl A.。;class B。.;class C:publA,public .。;从定义格式上来看,多重继承与单继承的区别主要是多重继承的基类多于一个。3.访问方式不管在单继承还是在多重继承的定义格式中,访问方式,即继承方式,可以为publi、pivte或protected,

3、如果省略,则默认为prvate方式。访问方式为ubli方式时,这种继承称为公有继承;访问方式为privae方式时,这种继承称为私有继承;访问方式为protcted方式时,这种继承称为保护继承。41。 派生类的生成过程在给出了派生类的定义和相应成员函数的实现代码后,整个派生类的定义就算完成了,这是就可以利用该类定义相应的对象处理实际问题了。由于派生类是在基类的基础上经过继承而产生的,所以搞清派生类中到底有哪些成员对于更好的使用派生类是很重要的.事实上,派生新类经历了三个步骤:吸收基类成员派生类继承吸收了基类的全部数据成员以及除了构造函数、析构函数之外的全部函数成员。也就是说,基类中的构造函数和析

4、构函数不能继承到派生类中的。2改造基类成员对继承到派生类中基类成员的改造包括两个方面:一是基类成员的访问方式问题,这由派生类定义时的访问方式来控制;二是对基类数据成员或成员函数的覆盖,也就是在派生类中定义了与基类中同名的数据成员或函数成员,由于作用域不同,于是发生同名覆盖,基类中的成员就被替换成派生类中的同名成员.3。添加新成员在派生类中,除了从基类中继承过来的成员外,还可以根据需要在派生类中添加新的数据成员和成员函数,以此实现必要的新功能。可以看出,在派生类中可以添加新成员的机制是继承和派生机制的核心,保证了派生类在功能上比基类有所发展。1。3 继承方式对基类成员的访问控制前面已经分析,派生

5、类继承和吸收了基类的全部数据成员和除了构造函数、析构函数之外的全部函数成员,但这些成员在派生类中的访问属性是可以调整的,这是由派生类定义格式中的继承方式来决定的,也就是继承方式控制了基类中具有不同访问属性的成员在派生类中的访问属性.由于继承方式可以有pub、privae和proeced三种,不同的继承方式会导致原来具有不同访问属性的基类成员在派生类中的访问属性也有所不同。这种访问包括两个方面:一是派生类中新增成员对从基类继承来的成员的访问;二是派生类的外部通过派生类的对象从基类继承来的成员的访问。1公有继承当类的继承方式为公有继承时,基类中pbic和protectd成员的访问属性在派生类中不变

6、,而基类privt成员不可访问.也就是说,基类的publc和protced成员在公有继承方式下分别继承为派生类的pblic和protectd成员,派生类中的其他成员可以直接访问它们,在派生类的外部只能通过派生类的对象访问从基类继承来的pulic成员.而无论是派生类的成员还是派生类的对象都无法访问从基类继承来的prvate成员。2.私有继承当类的继承方式为私有继承时,基类中的pub和protd成员都以rvate成员出现在派生类中,而基类prit成员不可访问。也就是说,基类的pblic和otced成员在私有继承方式下被继承为派生类的pra成员,派生类中的其他成员可以直接访问它们,但在派生类的外部无

7、法通过派生类的对象访问它们。而无论是派生类的成员还是派生类的对象都无法访问从基类继承来的ivte成员.可以看出,经过私有继承后,所有基类的成员都成为派生类的私有成员,如果进一步派生的话,基类的成员就无法在新的派生类中被访问。因此,经过私有继承后,基类的成员再也无法在以后的派生类中发挥作用,实际是相当于中止了基类功能的继续派生。.保护方式当类的继承方式为保护继承时,基类中的pubic和rotete成员都以roteted成员出现在派生类中,而基类ivat成员不可访问.也就是说,基类的publc和procted成员在保护继承方式下被继承为派生类的prtecd成员,派生类中的其他成员可以直接访问它们,

8、但在派生类的外部无法通过派生类的对象访问它们。而无论是派生类的成员还是派生类的对象都无法访问从基类继承来的pivate成员。继承访问方式基类成员特性派生类成员特性公有pulcpublicpoctdpriatepubirotete不可访问私有privatpubiproeprivateriterte不可访问保护protectedpubiprteprivaterotectdrotcted不可访问示例:#includeiosteam。”la Apubl:vid f1();rteted:it j1;prvat:in i1;clas Bpublic:oid ();voi f();proted:int j2

9、;int j1;rvat:in i;clss B:blic ublic:void f2();roted:int2;pvte:it i2;;lass C:public Bpublc:oid f3();cls C:pblic Bpubic:vod f(); oid 1(); oid f2();ptected: int 1,j;回答如下问题: 的成员函数f2()能否访问A中的f()、i1、j等成员?的对象1能否访问A中的f1()、i1、j等成员? C的成员函数f3()能否访问B中的f2()、2等成员?能否访问A中的f1()、i1、j1等成员? 的对象能否访问中的f2()、i、j2等成员?能否访问中的

10、f()、i1、j等成员? 从上述过程可得出对公有访问继承什么样的结论?解答: B的成员函数f2()能访问A中的f1()、j1,不能访问i1。B的对象b1能访问A中的f1(),不能访问i1、1. C的成员函数f3()能访问B中的f2()、2,不能访问i2。能访问A中的f1()、1,不能访问i1。 C的对象能否访问B中的f2()和中的f1(),其他均不可访问。 在公有继承时,派生类的成员函数可以访问基类中的公有成员和保护成员;派生类的对象仅可访问基类中的公有成员。示例:iclude ”iostreamhclas Apblic:void f(in i)ouend;void g()cout”g”end

11、l;class B:Apulic:oi h()oth”;::;;oid min() 1;d。f(6);/d1.g();1。h();运行结果:6h示例:#nclde ote.”inclde ”sting.hcls Apublic:(const har nm)strcy(name,nm);/private:proeted:charame;clas B:public Apublic:(costhar nm):(nm)vod PrinNam()const;void B::PitName()conscutname:”namendl;oid min() b1(Wang Li”);b1Pintam();4。

12、4 派生类的构造函数和析构函数继承和派生的机制可以使派生类继承基类的成员,从而实现了原有代码的重用,但是,由于基类的构造函数和析构函数不能继承,那么在派生类中,如果对派生类新增的成员进行初始化,就必须在派生类中根据需要加入新的构造函数,如果对从基类继承下来的成员进行初始化,还必须由基类的构造函数来完成,所以需要在派生类中的构造函数,一方面负责调用基类的构造函数对基类成员进行初始化,另一方面还要负责对基类的构造函数所需要的参数进行必要的设置.单继承方式下派生类构造函数的定义在单继承方式下,派生类的构造函数的定义格式如下:派生类名::派生类构造函数名(形参表):基类构造函数名(参数表),子对象名(

13、参数表)./派生类构造函数的函数体;在此定义格式中,派生类构造函数名后面括号内的参数表中包括参数的类型和参数名,而基类构造函数名后面括号内的参数表中只有参数名而没有参数类型,并且这些参数必须是来源于派生类构造函数名后面括号内的参数.示例:icud ”otream.h”as Apvate:int ;public:A()a=0;coAs fal consuctr caled。nl; A(in i) =i;ouAs constrctor calld.”enl;() cot”s detrutor called.”endl; voidPrint() cost coua,; it ta()reura;;c

14、lass B:blic ivte:i b;A a;ublic:B()b;cout”s defaul costrucorclled。el; (in i,itj,it k);B()cot”Bs destuctrclleenl; oi rin();:B(in ,i j,itk):A(i),a(j)b=k;tBs cnstructor clled.”endl;void B:ri()A::Print();coutb”,”a.Gta()endl;vidmain()Bbb2;bb0=B(1,2,);bb1=B(3,4,);or(it 0;2;i+)bi。Pin();运行结果:Adeaultcontucrcl

15、e。As dealt constructor alled. default cntructr alled.Asdefaul constror calledAs ealt constructr clled。Bs fault costruo cle.As strutr clle。As costrutr called。Bs ontuctorcalled.B derutr called。A desrucor cled.As detructo clled。Asntrucrcall.Aconsrutor clled。 contuctorcaed。Bs desructorcalledAs dtutorcal

16、eAs etrutor lled.1,5,2,7,4Bs dstrctoalle。sdstrucorclled。As destuctor calle.Bs destructor lled。As desutorcaed。As destcto cald.说明:该程序中先定义了类,接着定义类B,它是类A的派生类。继承方式为公有继承。 派生类B的构造函数格式如下:B:B(int i,it j,itk):A(),aa(j)b=;coutBs cnstrcocalled”end;其中,B是派生类构造函数名,它的参数表中有3个参数:参数i用来初始化基类的数据成员;参数用来初始化类B的子对象a;参数用来初始化

17、类中数据成员b。冒号后面的是成员初始化列表,如果该表中有多项,它们用逗号分隔。该成员初始化列表的顺序如下:先是基类构造函数;再是派生类中子对象类的构造函数;最后是派生类的构造函数。故亦可写成如下形式:B::B(int i,n j,in ):A(i),aa(j),b(k)/b=k;cs contctor cale。endl; 运行结果分析:先创建两个对象元素的对象数组。调用两次类B的缺省构造函数,每调用类B的缺省构造函数时,先调用两次类A的缺省构造函数和一次类B的构造函数。于是出现了输出结果的前行。接着,程序中出现两个赋值语句,即给两个已定义的对象(对象数组元素)赋值。系统要建立一个匿名对象,通

18、过构造函数对它初始化,并将其值赋给已定义的左值对象,再调用析构函数将匿名对象删除。因此输出结果中出现两个调用派生类B的构造函数和析构函数的2行信息.输出两个类对象的数据成员值,占有2行信息。最后,程序结束前由系统自动调用派生类的析构函数,显示输出了删除两个对象的6行信息.2多重继承方式下的派生类构造函数的定义在多重继承方式下,派生类的构造函数必须同时负责所有基类构造函数的调用,对于派生类构造函数的参数个数必须同时满足多个基类初始化的需要。所以,在多重继承方式下,派生类的构造函数的定义格式如下:派生类名::派生类构造函数名(参数表):基类名1(参数表1)基类名2(参数表2)子对象名(参数表)/派

19、生类构造函数的函数体其中,第个参数表中的参数包含了其后的各个参数表中的参数。3.派生类构造函数的执行次序派生类构造函数执行的一般次序为: 调用基类构造函数,调用顺序按照它们被继承时说明的顺序(从左到右),而不是按派生类构造函数在初始化表中的次序; 调用子对象的构造函数(如果在派生类中存在子对象的话),调用顺序按照它们在类中说明的顺序;执行派生类构造函数的函数体。当派生类的对象被删除时,派生类的析构函数被执行.由于基类的析构函数不能被继承,因此在执行派生类的析构函数时,基类的析构函数也将被调用。而执行顺序是先执行派生类的析构函数,再执行基类的析构函数,其顺序与执行构造函数是的顺序正好相反.示例:

20、clue”istream.hclass1priate:nt b1;lic:1(inti)b1i;coutconstrctr B1”il;vdpi() coutbendl; ;clasB2pivt:inb2;public:2(int i)i;cout”onstructoB2。”end;vi rin() cb2endl; ;cls B3private:n ;pbl:B3(inti)b3=i;utconstrucor 3。ien;itetb3() turn b; ;las A:pulc,ublic B1prvte:it a;3 b;ublic:A(nt i,int j,ntk,int ):B(i),

21、B2(j),bb(k),a(l)/a=l;cotonstructor A.endl;vod print()B1:pt();B2::prin();couta”,bbgtb3()ndl;intan(void) aa(1,2,4);aa.pint();etrn 0;运行结果:costructor .cntuctoB1csutr 3cntrucor A.124,3es ay key to conn说明:派生类A的构造函数定义如下:A(int i,ntj,in k,nt ):B1(i),B2(j),bb(k)al;cou”cnstuctor A。ndl;该函数的总参数表中参数有个,分别是基类B1,基类B

22、,子对象bb以及派生类A构造函数的参数,亦可写成如下形式:A(int i,it,n k,int ):B(),B2(),bb(k),a(l)coutconstructrAlnl; 派生类构造函数的执行顺序:在构造函数的成员初始化表中,两个基类顺序是1在前,2在后。而定义派生类A时的两个基类顺序是B在前,1在后。输出结果中,可以看出,先执行B的构造函数,后执行B1的构造函数。因此,执行基类构造函数的顺序取决于定义派生类时基类的顺序.可见,派生类构造函数的成员初始化列表中各项顺序可以任意排列。 作用域运算符::在该程序中用于解决作用域冲突问题很明显.在派生类A中的prit函数中,分别使用了B:pri

23、t();和B2::print();。4。2 派生中成员的标识与访问在多重继承的情况下,派生类具有两个以上的直接基类,而这些直接基类的一部分或全部又是从另一个共同基类派生而来的,这些直接基类中从上一级基类继承来的成员拥有相同的名称,在派生类的对象中,这些同名成员在内存中同时拥有多个拷贝,如何进行分辨呢?有两种方法,一是使用作用域运算符唯一标帜并分别访问它们;二是将直接基类的共同基类设置为虚基类.2. 使用作用域运算符这种方法就是在需要访问的成员名前加上直接基类名和作用域运算符“::”。其格式是:直接基类名::数据成员名直接基类名::成员函数名(参数表)示例:#nclude ostrea”lass

24、Apublc:nt ;id fa() cota=andl; ;cls:pblic Abic:i b;clsC:publi Aubi:itc;class D:pbic B,pblic Culc:int ;voi fd() cot”d=dendl; ;oidman()D;dd。d=1;dfd();d.B:a2;dd。B:f();dd.C:a=;dd。C::fa();运行结果:d1=2a=3Press y eyto coinu说明:该示例中的继承关系和D对象结构分别如下:Aint a;void fa();Bint b;Cint c;Dint d;void fd();Dint B:a;int C:a;

25、int B:b;int C:c;int d;void B:fa();void C:fa();void fd();2 虚基类该方法就是将直接基类的共同基类设置为虚基类,即在基类的访问方式前加上关键字“rtul“,声明虚基类的格式如下:cass 派生类名:virtua 访问方式 基类名 /声明派生类成员;虚基类虽然被一个派生类间接地多次继承,但派生类却只继承一份该基类的成员,这样就避免了在派生类中访问这些成员时的二义性。示例:#iclde iostrem.hclassAlic:in a;oid fa() cout”dl; ;css B:vitalpublic Apublic:intb;cass C

26、:vrtul pbiAlic:ntc;clsD:pulic B,pbic Cpulic:in d;vodfd() cut=a; ingea2() etrn a; ;void m()A aa();A*p&aa;cut”paend;coua=aa。gt1()edl;couta=aa。geta2()en;运行结果:a=8a=8a=8res an key oconin引入派生类后的对象指针引入派生类后,由于派生类是由基类派生出来的,派生类和基类息息相关。因此,指向派生类和基类的指针也是相关的。在引入派生概念后,任何被说明为指向基类对象的指针,都可以指向它的公有派生类。示例:#icludeiosam.h

27、#include ”string.hcspivate:char *name;t ength;public:A(har *s)en=tlen(s);nae=new hareg+;trpy(name,);void o() cotnedl; ;s :public rite:it age;publi:B( st,t g):A(sr)B::g=age;voidshow()A::how();coutth age:”geend;;vod an()A s1(Smith),p1;B 2(en”,20),p2;p1=s1;ho();1=&s2;1-show();p2=s2;how();运行结果:ihJeanJea

28、e age is:2Pres an eytocontine4。3 多态性和虚函数封装性是基础,继承性是关键,多态性是补充.所谓多态性是指发出同样的消息被不同类型的对象接收时将导致不同的行为。这里所说的消息是指对类的成员函数的调用,不同的行为是指不同的实现.函数重载和运算符重载是简单的一类多态性。建立是虚函数的概念和方法基础之上的是较复杂的一类多态性。函数重载已在前面讨论过,不再重复。4.3。1 运算符重载运算符重载是指可以赋予已有的运算符多重的含义。C+中通过重新定义运算符,使它能够用于特定类的对象执行特定的功能.1。运算符重载的几个问题 哪些运算符可以用作重载几乎所有的+运算符都可以用作重载

29、。但有几个运算符不允许重载:成员选择符 成员指针选择符.域作用符: 三目运算符?: 运算符重载后,优先级和结合性的变化是怎样的用户重新定义运算符,不改变原运算符的优先级和结合性。也不改变运算符的语法结构,即单目运算符只能重载为单目运算符,双目运算符只以重载为双目运算符。编译程序如何选用哪一个运算符函数运算符重载实际是一个函数,所以运算符的重载实际上是函数的重载。编译程序对运算符重载的选择,遵循着函数重载的选择原则。当遇到不明显的运算符时,编译程序将去寻找参数匹配的运算符函数。 重载运算符有哪些限制a不可以臆造新的运算符.必须把重载运算符限制在+语言中已有的运算符范围。b重载运算符坚持四个不改变

30、:运算符操作数个数、优先级、结合性、语法结构。运算符重载时必须遵循的原则a重载运算符含义必须清楚。.不能有二义性。2。运算符重载函数的格式单目操作符重载函数的定义格式和调用格式分别为:返回值类型 oraor (形参)单目操作符 (实参)双目操作符重载函数的定义格式和调用格式分别为:opertr 双目操作符 (形参,形参) 实参双目操作符 实参或perat (实参1,实参2)运算符重载函数的两种形式下面的两种形式的重载都可以访问类中的私有成员。重载为类的成员函数inclue”isrea。h”lss coplxrat:due real,iag;ublic:comlex() ea=imag=; om

31、pex(dube r,oube i)rea=r;iag=i;comlexpetor +(cnt comex &c);cle opror (cont come &);comple opertor (cnstomlx c);omplex optor /(conscomplex &c);fied voi prit(onst oplx c);line omlex cmpl::perato (cscomplex&c)retunmple(real+c.real,im+cimag);line compexcomplex::oprator(nst cplex c)reurn opex(realc。rea,im

32、agiag);inlin mplxcompex::erao (const cmpex &c)retrn complx(e*c。imagc.ima,relc.ia+a*c。l);ilie coplomlex::perat /(cnst mlex &c)turncomle(eal.real+iagc。iag)/(c.real*real+.iag*c.img),(magc.realrealc.mg)(c。real.real+cimagc。imag);oid prnt(cons copl c)if(。ig0)cutc.ealimag”;escoutc.eal”。imag”i;void in()cmpl

33、ex c1(0,3。0),(4。0,2),c3;c3=c1+c2;outenl1c2 = ”;prit(c3);c3=1-c2;coutendl”c1c2 = ;rn(c);c3c1c;coutnl”c2 =”;rint(3);c3=c1c2;coutenlc1/c2 = ;prit();c3(c1+c)*(c1)2/c;coutendl(c1+2)(c1-c2)*2/c =;pit(c);cotdl;运行结果:c1+c 6+112= -+ic1*214+81/c2 0.1+0。8i(c1+c2)*(c1c2)*c2/1 = 1.86+25.23iress ankey t conine说明:该

34、程序中定义了一个compe类,该类中定义了4个成员函数作为运算符重载函数。将运算符重载函数说明为类的成员函数的格式如下:类名 oerator运算符(参数表)其中的oerator是运算符重载的关键字。程序中出现的表达式:c1+c,编译程序将解释为:c.operaor(2),其中,1和2是comple类的对象。operator +()是运算符+的重载函数。 重载为友元函数示例:#incl ostream。h”ssomlexprivate:duble real,iag;uic:complex() eal=iag=0; cmpex(ole,double i)rea=r;img=i;fried mpl

35、perator +(const cop 1,cont compex&2);frind coplex perator -(constcomle &c,constcomple2);fried comex oeraor (cst omplex c1,ont compexc2);frendcmpex etor /(cons omlex &1,const cmplex &c2);frend void it(cost cmplx c);comex peator +(const coplex c,onst cmple c2)turncompx(c1.rel2。real,1imag+c2。im);compx

36、opeator (const comple &c,cotmpex&c2)return omplex(c.real-c.real,c1.mgc2。imag);comlepertr (con complx 1,constomle c2)tun coex(c1.eal*c2.ralc1.a2.ima,c.real*c2imag+c1.ia.eal);cmplex orator (cotcompex&c1,ons ople c)tn cle((c1realc2。ral+1.mag*c。iag)/ (c.re*2.real+c2。mg2.imag), (c。img*c2.realc1.relc2。iag

37、)/ (c2real*c2relcimag*c2.g));vid print(constcomlex &c)if(cmag)coutc.ral.imagi;elecoutreal”+c。imagi;d mai()complex c1(.0,.0),2(.0,2。),c;c3=1+c2;cotendlc1+2= ;print(c3);c3c1c2;otndlc1c2 = ;rint(c3);cc1*c2;cotdc12= ”;prt(c3);=/c2;coutendlc1/ ;pri(c3);3=(c+c2)(1c2)2/c1;otenl(1+2)(c12)c/c = ;rint(c);cuen

38、dl;运行结果:c+c2 1ic1-c2 = -2+5ic1c= 48ic/2 =010。8i(1+c2)(cc2)*c21 31。8425.38ires y etcontinue两种重载形式的比较一般而言,单目运算符最好重载为成员函数,双目运算符最好重载为友元函数。4。3.2虚函数在讨论虚函数之前,先讲一讲静态联编和动态联编.联编是指一个计算机程序自身彼此关联的过程.按联编所进行的阶段不同,可分为两种不同的联编方法:静态联编和动态联编。静态联编是指联编工作出现在编译连接阶段,又称之为早期联编或静态束定。动态联编是指联编工作出现在程序运行阶段,又称之为晚期联编或动态束定,静态联编示例:incu

39、d iosrem。hcassointbic:point(b ,dulej) x=i; yj; oble r() consreturn .; piat:dule ,;;lass recage:pbliponprive:oble w,;pblic:ecngle(doube i,oble j,doulek,doble l);doue ea()constreturn wh; ;rae::rectange(oubei,doble j,doubek,doble l):pint(,)w=; hl;vo un(pint s)cts.area()edl;vid man()rctng re(3,5,15。,25.

40、0);n(r);运行结果:输出结果表明:在fun()函数中,所引用的对象执行的are()操作被关联到pint:aa()的实现代码上.这是因为静态联编的结果。在程序编译阶段,对s所引用的对象所执行的area()操作只能束定到point类的函数上.因此导致了输出不期望的结果。因为我们期望的是s引用的对象所执行的are()操作应该束定到retage类的rea()函数上.这是静态联编所达不到的。为了解决这一问题,+引入虚函数概念.虚函数是动态联编的基础。虚函数是成员函数,而且是非static的成员函数.说明虚函数的方法如下:vrtl (参数表);如果某类中的一个成员函数被说明成虚函数,这就意味着成员函

41、数在派生类中可能有不同的实现。当使用这个成员函数操作指针或引用所标识的对象时,对该成员函数调用采取动态联编方式。虚函数示例:#iclude”iosream。hclas ointpubic:n(double i,oblej) i; y=j; virtul douleaea() cn tu 0。0; prae:double x,y;;clas ectae:pub oirae:dobw,h;publ:rectagle(dobl i,doubej,double k,doule );virtul doble area() constreu wh; ;recange:retagle(doule i,dou

42、bl j,dule k,du l):point(i,)=k; h=l;void fun(poin &)cots.are() vrtral类型 函数名 ()=0; .。;在许多情况下,在基类中不能对虚函数给出特定的有意义的实现,而把它写成纯虚函数,它的实现留给该基类的派生类去做。2.抽象类我们称带有纯虚函数的类为抽象类。抽象类是一种特殊的类,它是为了抽象和设计的目的而建立的,它处于继承层次结构的较上层。抽象类是不能定义对象的,在实际中为了强调一个类是抽象类,可将该类的构造函数说明为保护的访问控制权限。3.虚析构函数在析构函数前面加上关键字virtual进行说明,称该析构函数为虚析构函数。如果一个基类的析构函数被说明为虚析构函数,则它的派生类的析构函数也是虚析构函数,不管它是否用virtu进行了说明。说明虚析构函数的目的在于在使用deete运算符删除一个对象时,能保证析构函数被正确地执行。因为设置虚析构函数后,可以采用动态联编方式调用析构函数。不足之处,敬请谅解43 / 24

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

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!