第4章多态性优秀课件.ppt
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_05.gif)
《第4章多态性优秀课件.ppt》由会员分享,可在线阅读,更多相关《第4章多态性优秀课件.ppt(88页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第4章多态性第1页,本讲稿共88页主要内容1.静态联编和动态联编2.运算符重载3.虚函数4.多态性带来的好处第2页,本讲稿共88页4.1概述所谓多态性多态性,就是不同对象收到相同的消息时,产生不同的动作。通俗地说,多态性是指用一个名字定义不同的函数,这些函数执行不同但又类似的操作,即用同样的接口访问功能不同的函数,从而实现“一个接口,多种方法”。第3页,本讲稿共88页1.几个重要的概念联编联编(Building):将函数调用链接上相应的函数体的代码,这一过程称为联编。静态联编静态联编(StaticBinding):是指系统在编译时就决定如何实现某一动作。即:静态联编要求在程序编译时就知道调用函
2、数的全部信息。优点优点:函数调用速度很快。动态联编动态联编:是指系统在运行时动态实现某一动作。即:采用动态联编时,系统要到程序运行时才能确定调用哪个函数。优点优点:提供了更好的灵活性、问题抽象性和程序易维护性。第4页,本讲稿共88页2.静态联编静态联编支持的多态性称为编译时多态性编译时多态性。在C+中编译时多态性是通过函数重载函数重载和模板模板体现的。利用函数重载机制,在调用同名的函数时,编译系统可以根据实参的具体情况确定所调用的是同名函数中的哪一个。利用函数模板,编译系统可以根据模板实参以及模板函数实参的具体情况确定所要调用的是哪个函数,并生成相应的函数实例;利用类模板,编译系统可以根据模板
3、实参的具体情况确定所要定义的是哪个类的对象,并生成相应的类实例。例例:见书第298页例10.1。第5页,本讲稿共88页例10-1重载函数的静态联编o在主函数main()中,对这些重载的成员函数有6处调用,这些调用反映了编译系统在完成联编时,区分重载函数的3种方法:o(1)根据实参特征来区分。例如,程序中的objD.Set(5);和objD.Set(A);o一个实参为整型常量5,一个为字符型常量A。o(2)根据对象的类型来区分。例如,程序中的oobjB.Who();和objD.Who();oobjB是类Base的对象,而objD是类Derived的对象,编译程序在编译时能够根据对象的类型,来决定
4、调用哪个函数。o(3)使用作用域分辩符加以区分。例如,程序中的oobjD.Base:Show();和objD.Derived:Show();o前者是调用objD中的直接基类中的Show()函数,而后者是调用派生类Derived的Show()函数。通过使用作用域分辩符,编译程序在编译时就能区分调用哪个函数。当然,直接使用objD.Show();调用的也是派生类Derived中的成员函数Show(),这是编译系统按照同名覆盖的原则决定的。第6页,本讲稿共88页2.动态联编动态联编所支持的多态性称为运行时多态性运行时多态性。在C+中,运行时多态性是通过继承继承和虚函数虚函数来实现的。为了达到动态联编
5、获得运行时多态性的效果,通常都是用指向基类的指针来调用派生类的虚函数。例例:见书第300页例10.2。第7页,本讲稿共88页派生类对象的地址赋值给指向基类的指针o#includeousingnamespacestd;oclassBaseopublic:ovoidWho()coutIambaseclass!endl;oclassDerived1:publicBaseopublic:ovoidWho()coutIamDerived1class!endl;oclassDerived2:publicBaseopublic:ovoidWho()coutIamDerived2class!Who();op=
6、&one_obj;o/基类指针p指向派生类Derived1的对象one_objop-Who();o one_obj.Who();op=&two_obj;o/基类指针p指向派生类Derived2的对象two_objop-Who();otwo_obj.Who();oreturn 0;oo程序的运行结果为:oI am base class!oI am base class!WHY?oI am Derived1 class!oI am base class!WHY?oI am Derived2 class!第8页,本讲稿共88页程序分析程序分析:从程序运行结果可以看出,指向基类的指针p,不管赋给它的是
7、基类对象base_obj的地址还是派生类对象one_obj和two_obj的地址,语句“p-Who();”调用的始终是基类中定义的版本。很明显,在这种情况下通过基类指针输出的结果并不是我们所需要的结果。我们希望指针p指向了对象one_obj后,输出的结果应为“IamDerived1class!”。造成以上结果的不统一原因是:在派生类Derived1中虽然继承了基类Base的成员函数Who(),但在派生类中又定义了一个同名的Who()函数,而这种改变在静态联编的条件下编译器并不知道。问题问题:那么,怎样获得我们所那么,怎样获得我们所希望的结果呢?希望的结果呢?第9页,本讲稿共88页解决方案解决方
8、案:必须通知编译器这种可能的改变,即需要进行动态联编动态联编。为了实现动态联编,C+提出了虚函数虚函数的概念。o虚函数:虚函数在基类中定义,在基类成员函数声明的前面加上virtual关键字(在派生类中重新定义该函数时不用加关键字virtual),即可把该函数声明为虚函数。第10页,本讲稿共88页将基类中某个成员函数声明为虚函数,并在派生类中重新定义从基类继承下来的虚函数后,当把派生类对象的地址赋给指向基类的指针变量时,用指向基类的指针变量来调用虚函数,则执行的就是派生类自己重新定义的函数版本。例例:将书第300页例10.2基类Base中的Who()函数定义为虚函数,即改写成virtualvoi
9、dWho()即可得到我们所希望的结果。I am base class!I am Derived1 class!I am Derived1 class!I am Derived2 class!I am Derived2 class!随着指针P实际指向的对象不同,使用语句P-Who();能够调用不同类中Who的相同版本,我们就可以用相同的界面P-Who()访问函数Who的多个实现版本,从而也就能够在程序运行时告诉用户,当时指针P实际指向何类对象。函数调用P-Who()依赖于程序运行时P的值。第11页,本讲稿共88页o把例10-2基类中的Who()函数定义为虚函数,即把程序中第六行的ovoidWho
10、()coutIambaseclass!endl;o改为:ovirtualvoidWho()coutIambaseclass!Who();”,由于赋给p的对象地址不同,使得能够实现调用不同Who()函数版本的方法。由于所调用函数Who()的版本是在程序运行时确定的,因此称为动态联编,这种多态性也称为运行时的多态性。第12页,本讲稿共88页4.2运算符重载引述引述:通常,在进行面向对象的程序设计时使用两种形式的重载:函数重载函数重载:是指在相同作用域内,若干个参数特征不同的函数使用相同的函数名,因此也称为函数名重载。(已经讨论过)运算符重载运算符重载:是指同样的运算符可以施加于不同类型的操作数上面
11、。当然,当参数特征不同或被操作数的类型不同时,实现函数的算法或运算符的语义往往是不同的。(本章讨论)第13页,本讲稿共88页1.运算符重载的方法和规则引例引例:见书第303页例10.3。#includeusingnamespacestd;classComplexpublic:Complex(doubler=0.0,doublei=0.0)real=r;imag=i;ComplexAdd(Complex&c);/复数的加法运算复数的加法运算ComplexSub(Complex&c);/复数的减法运算复数的减法运算voiddisplay();/复数输出复数输出private:doublereal;
12、doubleimag;第14页,本讲稿共88页ComplexComplex:Add(Complex&c)returnComplex(real+c.real,imag+c.imag);ComplexComplex:Sub(Complex&c)returnComplex(real-c.real,imag-c.imag);voidComplex:display()cout(real,imag)endl;第15页,本讲稿共88页intmain()Complexc1(5,10),c2(1.5,2.5),c3;coutc1=;c1.display();coutc2=;c2.display();c3=c1.
13、Add(c2);/c3=c1+c2;coutc1+c2=;c3.display();coutc1-c2;c3=c1.Sub(c2);/c3=c1-c2;c3.display();return0;第16页,本讲稿共88页o使用函数调用方式完成复数的算术运算,与人们习惯相差较远。o能否在程序中使用人们习惯的表达式“c1+c2”来完成复数c1和c2的相加?对运算符“+”进行重载!o运算符重载是对已有的运算符赋予多重含义,使同一个运算符作用于不同类型的数据时,行为不同。第17页,本讲稿共88页1)运算符重载的方法运算符重载的方法运算符重载的方法是定义一个重载运算符的函数,在需要被执行重载的运算符时,系
14、统就自动调用该函数,以实现相应的运算。即:运算符重载是通过定义函数实现的,其本质就是函数重载本质就是函数重载。o 实现过程:首先把指定的运算表达式转化为对运算符函数的调用,运算对象转化为运算符函数的实参,然后根据实参的类型来确定需要调用的函数,这个工作是在编译过程中完成的。重载后运算符对自定义类型操作数的处理,实际上是通过函数调用来完成的,是函数调用的一种特殊形式。我们把用来重载运算符的成员函数或友元函数,统称为运算符函数。第18页,本讲稿共88页运算符的重载形式有以下两种:重载为类的成员函数;重载为类的友元函数。运算符重载为类的成员函数运算符重载为类的成员函数o一般语法形式为:函数类型ope
15、rator运算符(形参表列)函数体;/对运算符的重载处理2)运算符的重载形式 “函数类型函数类型”指定了重载运指定了重载运算符的返回值类型,也就是运算算符的返回值类型,也就是运算结果类型。结果类型。“operator”是定义运算符是定义运算符重载函数的关键字。重载函数的关键字。“运算符运算符”给定了要重给定了要重载的运算符名称,必须是载的运算符名称,必须是C+中可重载的运算符。中可重载的运算符。o必须放在类X的公有段第19页,本讲稿共88页参数表中列出该运算符所需要的操作数,如下所述:(1)重载一元(一目)运算符时,参数表为空。在这种情况下,当前对象(即,调用该运算符函数的对象)作为该运算符唯
16、一的操作数。(2)重载二元(二目)运算符时,参数表中有一个参数。在这种情况下,当前对象作为该运算符的左操作数,参数作为右操作数。不难看出,当使用成员函数重载运算符时,定义运算符函数的方法与定义普通成员函数的方法基本相同,唯一差别是,运算符函数的名字必须为operator(为任何一个被重载的运算符),而不能由程序员随意为运算符函数起名字。第20页,本讲稿共88页重载后运算符的语义:(1)一元运算符的语义。如果针对类X重载了一元运算符,xobj是X类的一个对象,则xobj或xobj的语义为:xobj.operator()(2)二元运算符的语义如果针对类X重载了二元运算符,而xobj1和xobj2是
17、X类的两个对象,则xobj1xobj2的语义为:xobj1.operator(xobj2)第21页,本讲稿共88页例例:复数类加减法运算重载为类的成员函数。classComplexpublic:Complex(doubler=0.0,doublei=0.0)real=r;imag=i;Complexoperator+(Complex&c2);/运算符运算符“+”重载为成员函数重载为成员函数Complexoperator-(Complex&c2);/运算符运算符“-”重载为成员函数重载为成员函数voiddisplay();/复数输出复数输出private:doublereal;doubleima
18、g;第22页,本讲稿共88页ComplexComplex:operator+(Complex&c2)Complexc;c.real=real+c2.real;c.imag=imag+c2.imag;returnc;ComplexComplex:operator-(Complex&c2)Complexc;c.real=real-c2.real;c.imag=imag-c2.imag;returnc;voidComplex:display()cout=0)cout+;coutimagiendl;第23页,本讲稿共88页intmain()Complexc1(5,10),c2(1.5,2.5),c3;
19、coutc1=;c1.display();coutc2=;c2.display();c3=c1+c2;/c1+c2解释为解释为c1.operator+(c2)coutc1+c2=;c3.display();coutc1-c2=;(c1-c2).display();/c1-c2解释为解释为c1.operator-(c2)return0;第24页,本讲稿共88页o例10-5单目运算符“+”的重载oTimeoperator+();/声明前置自增运算符“+”重载函数(+i)一元运算符oTimeoperator+(int);/声明后置自增运算符“+”重载函数(j+)二元运算符nC+语言的新标准规定,为了
20、把运算符+(或-)重载为前缀形式,应该把它当作一元运算符来重载。把运算符+(或-)重载为后缀形式,应该把它当作二元运算符来重载。o程序中,重载后置自增运算符时,多了一个int型的参数,增加这个参数只是为了与前置自增运算符重载函数有所区别,此外没有任何作用。第25页,本讲稿共88页运算符重载为类的友元函数运算符重载为类的友元函数般语法形式为:friend函数类型operator运算符(形参表列)函数体;/对运算符的重载处理第26页,本讲稿共88页用友元函数重载运算符用友元函数重载运算符与成员函数重载相比主要有以下几点差别:(1)在函数原型前多了一个关键字friend。(2)由于是友元函数,因此在
21、类X的公有段和私有段说明此函数的效果相同(而若作为成员函数说明运算符函数,则必须放在类X的公有段)。(3)参数个数问题:由于这样说明的运算符函数是类X的友元函数而不是成员函数,因此它没有this指针。由此,必须在参数表中显式列出每一个操作数。因此,用友元函数重载运算符时参数表中参数个数,比用成员函数重载运算符时参数表中的参数个数多一个。n重载一元运算符时参数表中应该有一个参数;n重载二元运算符时参数表中应该有两个参数,其中第一个参数作为左操作数,第二个参数作为右操作数。第27页,本讲稿共88页用友元函数重载运算符用友元函数重载运算符(1)一元运算符的语义。如果在类X中重载了一元运算符,xobj
22、为X类的一个对象,则xobj或xobj的语义为:operator(xobj)(2)二元运算符的语义。如果在类X中重载了二元运算符,而xobj1和xobj2是X类的两个对象,则xobj1xobj2的语义为:operator(xobj1,xobj2)第28页,本讲稿共88页例例:将复数加减法运算重载为友元函数。o例10-6将复数加法运算重载为友元函数nfriendComplexoperator+(Complexc1,Complexc2);/运算符“+”重载为友元函数nfriendComplexoperator+(Complexc1,doublec2);/运算符“+”重载为友元函数nfriendCo
23、mplexoperator+(doublec1,Complexc2);/运算符“+”重载为友元函数n若要修改c1或c2对象的值,则必须用引用参数:nComplex&c1或Complex&c2第29页,本讲稿共88页例例:将复数加减法运算重载为友元函数。classComplexpublic:Complex(doubler=0.0,doublei=0.0)real=r;imag=i;/运算符运算符“+”重载为友元函数重载为友元函数friendComplexoperator+(Complex&c1,Complex&c2);/运算符运算符“-”重载为友元函数重载为友元函数friendComplexop
24、erator-(Complex&c1,Complex&c2);/复数输出复数输出voiddisplay();private:doublereal;doubleimag;第30页,本讲稿共88页Complexoperator+(Complex&c1,Complex&c2)returnComplex(c1.real+c2.real,c1.imag+c2.imag);Complexoperator-(Complex&c1,Complex&c2)returnComplex(c1.real-c2.real,c1.imag-c2.imag);voidComplex:display()cout=0)cout
25、+;coutimagiendl;第31页,本讲稿共88页intmain()Complexc1(5,10),c2(1.5,2.5),c3;coutc1=;c1.display();coutc2=;c2.display();c3=c1+c2;/c1+c2 解释为解释为operator+(c1,c2)coutc1+c2=;c3.display();c3=c1-c2;/c1-c2 解释为解释为operator-(c1,c2)cout”。下列两个运算符只能用友元函数重载,不能用成员函数重载:“”。第34页,本讲稿共88页3)运算符重载的规则_IC+不允许用户自己定义新的运算符,只能对已有的C+运算符进行
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 多态性 优秀 课件
![提示](https://www.taowenge.com/images/bang_tan.gif)
限制150内