C语言试题、学习、考试大全.ppt_第1页
C语言试题、学习、考试大全.ppt_第2页
C语言试题、学习、考试大全.ppt_第3页
C语言试题、学习、考试大全.ppt_第4页
C语言试题、学习、考试大全.ppt_第5页
已阅读5页,还剩53页未读 继续免费阅读

下载本文档

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

文档简介

目录,第1章C+概述第2章数据类型、运算符和表达式第3章简单的输入/输出第4章C+的流程控制第5章函数第6章编译预处理第7章数组第8章结构体、共同体和枚举类型第9章指针和引用第10章类和对象第11章类和对象的其他特性第12章继承和派生第13章多态性第14章输入/输出流第15章模板,第一部分面向过程的程序设计,第二部分面向对象的程序设计,第13章多态性,13.1函数重载13.2运算符重载13.3静态联编13.4动态联编和虚函数13.5纯虚函数和抽象类,第13章多态性,多态性是实现OOP的关键技术之一。,在C+中,多态性分为两种:静态多态动态多态,函数重载和运算符重载属于静态多态。函数重载:相同函数名可以完成不同功能。运算符重载:相同运算符完成不同功能。,动态多态是指:程序执行过程中确定的关系,如动态确定函数的调用关系。,运行时的多态(动态多态)是通过类的继承和虚函数来实现的。,13.1函数重载参见5.6节(略),13.2重载运算符,C+中所有的运算符都已预先定义了用法及意义。如:+*/=等,适用于已有的数据类型。,已定义的用法及意义是不允许用户改变的。,如果用户定义了新的数据类型,希望已定义的运算符能适应新的数据类型,,如:前述Complex类的加法运算,Complexc1,c2,c3;c3=add(c1,c2);/以前通过函数实现加法运算c2.add(c3);/或通过成员函数实现c3=c1+c2;/能否直观地写成这样?,能!运算符的重载可以达到此目的。,允许重载和不允许重载的运算符见13-1和13-2表。,13.2.1运算符重载的几点说明,重载运算符的限制(1)只能对已有运算符重载,不可臆造新的运算符。(2)不允许改变运算符的优先级和结合性。(3)不允许改变运算符的语法结构,如二元运算符只能重载成二元运算符,一元运算符只能重载成一元运算符。,1.重载为类的成员函数,在类内定义运算符重载函数的格式为:operator(),以operator为关键字,编译器可以很容易将运算符重载函数与其他成员函数区别开来。,例13.2实现复数类的“+”,“-”等重载运算关键部分见下页,13.2.2运算符重载的两种方式,在类外定义运算符重载函数的格式为::operator(),classComplexfloatReal,Image;public:.Complexoperator+(constComplex,voidmain()Complexc1(2,3),c2(4,-2),c3;c3=c1+c2;c3=c1+5;c3=-c1;,编译器将c1+c2解释为:c1.operator+(c2),将c1+5解释为:c1.operator+(5),第1个运算量是对象,第2个运算量是参数。,阅读教材上程序全文(讲解略),将-c1解释为:c1.operator(),当用成员函数实现运算符的重载时,重载函数的参数个数只能是0个或1个。分别实现:一元、二元运算符的重载。,2.重载为友元函数,例13.3用友元函数实现复数类的“+”和“”重载运算关键部分见下页,classComplexfloatReal,Image;public:.friendComplexoperator+(constComplex,在main()函数中,若有Complexc1,c2;则编译器将c1+c2解释为:operator+(c1,c2),将c1解释为:operator(c1),阅读教材上程序全文(讲解略),当用友元函数实现运算符的重载时,重载函数的参数个数只能是1个或2个。分别实现:一元运算符重载、二元运算符重载,3.两种重载方式的比较,因此:对一般的二元运算符重载为友元函数比重载为成员函数更优越。但是对于赋值运算符,将其重载为成员函数较好,因为赋值运算符是一个二元运算符,其语法格式为=,第一个运算量必须是对象(变量也是对象),通过对象调用成员函数比较自然。若重载为友元,则可能会出现5.6=c这样的表达式,与赋值表达式的语义不一致。,定义友元的目的是在友元函数中直接访问类的私有成员,实际上,也可以通过公有函数接口访问类的私有成员,所以实现运算符重载,可以即不用成员函数,也不用友元函数。,classComplexfloatReal,Image;public:Complex(doubler=0,doublei=0)Real=r;Image=i;voidSetReal(doubleReal)Complex:Real=Real;voidSetImage(doubleImage)Complex:Image=Image;doubleGetReal()return(Real);doubleGetImage()return(Image);,4.使用非成员、非友元实现运算符的重载,例13.4:,Complexoperator+(Complex,编译器将c1+c2解释为:operator+(c1,c2),对于Complex类,如有Complexc1(2,3),c2;则自动将c2=c1;处理成:c2.Real=c1.Real;c2.Image=c1.Image;一般不会出现问题。,5.何时必须重载=和+=运算符?,相同类型的对象之间是可以直接赋值的,C+将赋值处理成两个对象的各个成员直接赋值。两个对象的对应数据成员逐一赋值。,例13.5在类中,用字符数组实现字符串。见“第13章多态性(例子).doc”,程序中A行使用赋值运算符进行对象整体赋值,C+将其处理成各个成员逐一赋值,如下图所示::,C+默认的处理是:strcpy(stud2.Num,stud1.Num);strcpy(stud2.Name,stud1.Name);stud2.Score=stud1.Score;。,但是如果对象的成员中有成员指向动态分配的数据空间就会出现问题。,例13.6在类中,用指针实现字符串,即字符串的空间是动态分配的。classStudentchar*Nump;/学号,注意:用指针实现char*Namep;/姓名,注意:用指针实现intScore;/成绩public:Student(char*nump=NULL,char*namep=NULL,intscore=0)if(nump)/构造函数Nump=newcharstrlen(nump)+1;strcpy(Nump,nump);/动态分配存储空间elseNump=NULL;if(namep)Score=score;,Student()/析构函数,释放指针指向的空间if(Nump)deleteNump;if(Namep)deleteNamep;voidShow()if(Nump,voidmain()Studentstud1(01201,Mary,88),stud2;stud2=stud1;/Astud1.Show();stud2.Show();cout.flush();/B,首先撤消对象stud2,然后撤消对象stud1,出问题!同一对象被撤销两次。,编译器将A行处理成:,解决办法,在类中增加赋值=重载函数:,Student/*this是对象自身,在赋值时,为目的对象的指针重新分配指向的字符串空间。,增加赋值=重载函数后,对象赋值后的存储空间如下:,这样,程序结束时,分别撤销两个对象,程序正确运行!,6对于+=(或=)运算符,重载函数的返回值为void类型或本类类型对象的区别,例13.7见“第13章多态性(例子).doc”,若重载为返回void类型,则本类对象不可连续赋值。若重载为返回本类类型,则本类对象可以连续赋值。,7对于+=(或=)运算符,返回本类对象与返回本类对象的引用的区别,比较下面两例,先看第一个例子:ComplexComplex:operator+=(constComplex此函数的返回值为本类对象,C+的处理是:用返回的对象值*this初始化内存临时对象(调用拷贝构造函数),从本函数返回后,用内存临时对象作为调用函数的结果。,再看第二个例子:ComplexComplex:operator+=(constComplexC+的处理是:调用拷贝构造函数,用返回的对象值temp初始化内存临时对象,内存临时对象作为调用函数的结果。,从上面两个小例子可以看出,若重载函数返回对象值,则返回*this和返回temp均可。但要注意,因为返回对象值时需要调用拷贝构造函数初始化内存临时对象,因此若对象有动态分配的存储空间,就必须定义拷贝构造函数。,第三个例子:Complex本例的返回值为本类对象的引用,不需初始化内存临时对象,返回值是对象自身,即*this。因为不需要初始化内存临时对象,效率较高,所以像+=、=等改变对象值的重载函数最好返回对象的引用。,第四个例子:Complex此时,出现问题。因为返回的是对象的引用(即对象自身,不借助于内存临时对象),系统要求在执行流程返回到调用处时,返回值是存在的。但是本例返回值是函数内部的局部对象temp,而局部对象在函数返回前,其空间是被撤消的。,结论:返回本类对象时,可以用对象自身和局部对象做为返回值(有时需要定义拷贝构造函数)。返回对象的引用时,不能用局部对象做为返回值。,例13.8对于字符串类,重载=运算符,返回对象自身的引用。就本例而言,可以不定义拷贝构造函数,程序能正确运行。见“第13章多态性(例子).doc”,8.调用拷贝构造函数和调用赋值运算符重载函数的时机,classComplexdoubleReal,Image;public:Complex(doubler=0,doublei=0)/构造函数Real=r;Image=i;Complex(Complex,程序的运行结果是?,调用了拷贝构造函数未调用拷贝构造函数,Callcopy23,只有在产生新对象时,调用构造函数。用已有对象初始化新产生的对象时,调用拷贝构造函数。赋值运算=,不调用拷贝构造函数。,13.2.3类型转换函数将本类对象转换成其他类对象,例:Complexc(3,2);doublex=6.2;如果有:c=x;/类型不一致或:x=c;/类型不一致则系统自动处理为:c=Complex(x);/需作类型转换x=double(c);/需作类型转换,构造函数:Complex:Complex(doubler)real=r;image=0;,定义类型转换函数:,功能:将类对象自动转换成类型对象,类型转换函数只能用成员函数实现,不能用友元函数实现。,例13.10类型转换函数的定义和使用#includeclassComplexdoubleReal,Image;public:Complex(doubler=0,doublei=0)Real=r;Image=i;operatordouble()/A类型转换函数,/将Complex类转换成double类returnReal;voidmain()Complexc(3,2);doublex;x=c;/Bcoutx=xendl;,/即x=double(c);,例13.11成员函数和类型转换函数的比较见“第13章多态性(例子).doc”,其中主函数为:voidmain(void)RMBr(23,8,6);intr1,r2,r3;r1=r;/处理成r1=r.operatorint();r2=int(r);/处理成r2=r.operatorint();r3=r.GetFen();coutr1=r1endl;coutr2=r2endl;coutr3=r3endl;,13.2.4其他运算符的重载1重载+、-运算符,重载前置+运算符的成员函数的一般格式为:,:operator+().,重载后置+运算符的成员函数的一般格式为:,:operator+(int).,重载前置+运算符的友元函数的一般格式为:,friendoperator+(strcpy(s1,s2);/不能写成s1=s2;strcat(s1,s2);/不能写成s1=s1+s2;能否定义一个字符串类:String实现:Strings1(abc),s2(123),s3;s1=s2;s3=s1+s2;能!可以利用C+提供的运算符重载实现。,例13.18定义字符串类String,并测试重载的运算符以及成员函数程序见“第13章多态性(例子).doc”,或阅读教材上的程序。,重点讲解:(1)说明:函数名后的const(2)(拷贝)构造函数,在主函数中如何使用?(3)重载赋值=运算符(4)重载+运算符(5)类型转换函数operatorconstchar*(6)删除子串图示见下页,删除子串:Stringoperator-(constStringdoubleadd(doublea,doubleb)/重载函数2return(a+b);voidmain()coutadd(1,2)t;/编译时确定调用重载函数1coutadd(1.1,2.2)n;/编译时确定调用重载函数2在编译连接阶段,就能根据参数的个数和类型确定调用的是哪一个函数。,例13.21读书上程序,重点讲解:doubleCalcArea(Point,能否找到一种机制,让CalcArea()函数变成一个通用的求面积的函数。这就是C+提供的动态联编和虚函数应完成的工作。,13.4动态联编和虚函数,运行阶段才能确定函数的调用关系,这就是动态联编,动态联编又称滞后联编、晚期联编,,动态联编技术能实现动态多态。,必须将类的成员函数定义成虚函数,才可以实现动态联编。,将成员函数定义成虚函数的格式为:virtual(),13.4.1虚函数,重点讲解:doubleCalcArea(Point,例13.22阅读书上程序,Area()是虚函数,C+规定,在A行保留相关的三个虚函数入口地址。在程序的运行阶段,根据实参的类型来确定调用哪一个虚函数。,通用的求面积函数,(1)派生类的虚函数必须与基类虚函数同名,且参数的类型、个数、顺序必须一致,否则,属于函数重载,而不是虚函数。,有关虚函数的说明:,(2)基类中虚函数前的关键字virtual不能缺省。,(3)必须通过基类对象的指针或引用调用虚函数,才能实现动态多态。,(4)虚函数必须是类的成员函数,不能是友元函数,也不能是静态成员函数。,(5)不能将构造函数定义为虚函数,但可将析构函数定义为虚函数。,(6)调用虚函数速度较慢。因为,要实现动态多态,在函数调用处必须保留多个虚函数的入口地址。,例13.23在成员函数中调用虚函数程序见“第13章多态性(例子).doc”,或阅读教材上的程序。,Bb;b.fun1();/调用A类的fun1()和fun2(),在A类的fun2()函数中,/在E行,this是指向b的指针,所以调用B的fun3()函数,classApublic:A()fun();virtualvoidfun()coutA:funt;classB:publicApublic:B()fun();voidfun()coutB:funt;voidg()fun();/在成员函数中调用虚函数;,例13.24在构造函数中调用虚函数,classC:publicBpublic:C()fun();voidfun()coutC:funn;voidmain()Cc;/依次调用A、B、C三类的缺省构造函数c.g();,运行结果:A:funB:funC:funC:fun,构造函数调用虚函数,调用的是类本身的虚函数。成员函数调用虚函数,遵循动态多态性原则。,13.4.2虚析构函数,如果类的构造函数中有动态申请的存储空间,在析构函数中应释放该空间。此时,建议将析构函数定义为虚函数,以便实现通过基类的指针或引用撤消派生类对象时的多态性。,#includeclassAchar*Aptr;public:A()Aptr=newchar100;A()/析构函数不是虚函数deleteAptr;coutDeleteAptrendl;,例:析构函数不是虚函数的情况,classB:publicAchar*Bptr;public:B()Bptr=newchar100;B()deleteBptr;coutDeleteBptrendl;voidmain(void)Bb;,输出结果:DeleteBp

温馨提示

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

评论

0/150

提交评论