《cpp08-多态性--运算符重载.ppt》由会员分享,可在线阅读,更多相关《cpp08-多态性--运算符重载.ppt(50页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、计算机学院 计算机网络与信息安全研究室 张荣博 ShenyangAerospaceUniversity第第8 8章章 多态性多态性8.1 多态性多态性8.4 纯虚函数纯虚函数()8.3 虚函数虚函数()8.2 运运算符重载算符重载()8.5 抽象类抽象类1ShenyangAerospaceUniversity多态性多态性q封装性、封装性、继承性继承性、多态性多态性构成了面向对象程序设计构成了面向对象程序设计的三大特性。的三大特性。q多态性是指发出多态性是指发出同样的消息同样的消息同样的消息同样的消息被被不同类型的对象不同类型的对象不同类型的对象不同类型的对象接收接收时有可能导致时有可能导致完全
2、不同的行为完全不同的行为完全不同的行为完全不同的行为。q多态的分类:多态的分类:重载多态重载多态通过函数重载来实现(包括运算符重载)通过函数重载来实现(包括运算符重载)强制多态强制多态通过强制类型转换实现。通过强制类型转换实现。包含多态包含多态通过虚函数来实现。通过虚函数来实现。参数多态参数多态通过模板来实现。(也叫泛型编程)通过模板来实现。(也叫泛型编程)2ShenyangAerospaceUniversity函数重载普通成员函数的重载普通成员函数的重载void max(int a,int b);void max(float a,float b);void max(float a,float
3、 b,float c);类成员函数的重载类成员函数的重载同一个类内的同名函数(参数表不同)。同一个类内的同名函数(参数表不同)。同名函数的隐藏同名函数的隐藏不同类内的同名函数。不同类内的同名函数。3ShenyangAerospaceUniversity运算符重载运算符重载的需要class Complex/复数类声明public:Complex(double r=0.0,double i=0.0);void display();/显示复数的值private:double real;double imag;4ShenyangAerospaceUniversity 如何实现两复数相加?Complex
4、ComplexCadd(ComplexCadd(Complex&a,Complex&b);&a,Complex&b);main()main()complexc1,c2;complexc1,c2;/复数类对象复数类对象复数类对象复数类对象 c1=c1=CaddCadd(c1,c2)(c1,c2);/调用函数计算两个复数的和调用函数计算两个复数的和调用函数计算两个复数的和调用函数计算两个复数的和 而数学中用“+”进行两个复数求和,“-”求差!C3=C1+C2;C=C1-C2;5ShenyangAerospaceUniversity运算符重载的定义q什么是运算符重载?什么是运算符重载?所谓运算符重载
5、就是所谓运算符重载就是赋予已有的运算符多重含义赋予已有的运算符多重含义。C+C+中预定义的运算符只适用于基本数据类型,而中预定义的运算符只适用于基本数据类型,而不适用于用户自定义类型(如类)不适用于用户自定义类型(如类).运算符重载运算符重载使运算符的运算对象扩充为自定义类型。使运算符的运算对象扩充为自定义类型。main()complexc1,c2;/复数类对象复数类对象c1=c1+c2;6ShenyangAerospaceUniversity运算符重载的实质运算符重载的实质q将指定的运算表达式转化为对运算符函数的将指定的运算表达式转化为对运算符函数的调用,运算对象转化为运算符函数的实参。调用
6、,运算对象转化为运算符函数的实参。q编译系统对重载运算符的选择,遵循函数重编译系统对重载运算符的选择,遵循函数重载的选择原则。载的选择原则。7ShenyangAerospaceUniversity运算符重载的规则1.1.只能重载只能重载C+C+语言中已有的、可以重载的语言中已有的、可以重载的运算符,不可臆造新的运算符。运算符,不可臆造新的运算符。+*(乘乘)/%&|!=+=*=/=%=&=!=&|+()-NewDeleteC+中不可以被重载的运算符:中不可以被重载的运算符:.:?:?:*(指针运算符指针运算符)8ShenyangAerospaceUniversity运算符重载的规则2.2.不改
7、变原运算符的优先级和结合性。不改变原运算符的优先级和结合性。3.3.不能改变操作数个数。不能改变操作数个数。4.4.经重载的运算符,其操作数中至少应该有经重载的运算符,其操作数中至少应该有一个是自定义类型。一个是自定义类型。int a=b+c*d;int a=b+c;Complex a,c;int b;c=a+b;9ShenyangAerospaceUniversity运算符重载的形式 运算符重载时,运算符重载时,运算符重载时,运算符重载时,运算符函数运算符函数运算符函数运算符函数具有两种方式:具有两种方式:具有两种方式:具有两种方式:类的成员函数类的成员函数类的成员函数类的成员函数 友员函数
8、友员函数友员函数友员函数 这两种方式非常相似,关键区别在于这两种方式非常相似,关键区别在于这两种方式非常相似,关键区别在于这两种方式非常相似,关键区别在于成员函数成员函数成员函数成员函数具有具有具有具有 this this this this 指针指针指针指针友员函数友员函数友员函数友员函数没有没有没有没有 this this this this 指针指针指针指针 不管用成员函数或用友员函数重载运算符,对运不管用成员函数或用友员函数重载运算符,对运不管用成员函数或用友员函数重载运算符,对运不管用成员函数或用友员函数重载运算符,对运算符的使用方法都是相同的。算符的使用方法都是相同的。算符的使用方
9、法都是相同的。算符的使用方法都是相同的。10ShenyangAerospaceUniversity运算符函数声明形式声明形式typeoperator(形参(形参1 1,形参,形参2 2,).Point operator=(const Point&Point operator=(const Point&srcsrc););Point operator+(Point a,Point b);Point operator+(Point a,Point b);Point operator+();Point operator+();11ShenyangAerospaceUniversity声明形式声明形式
10、typeoperator(形参(形参1 1,形参,形参2 2,).重载为重载为类成员函数类成员函数时时 参数个数参数个数=原操作数个数原操作数个数-1-1(后置(后置+、-除外)除外)重载为重载为友元函数友元函数时时 参数个数参数个数=原操作数个数原操作数个数,且至少应该有一个自定,且至少应该有一个自定义类型的形参。义类型的形参。12ShenyangAerospaceUniversity二元运算符二元运算符对任意二元运算符对任意二元运算符 :aabb如如:aa+bbaa+bb可以解释为:可以解释为:aaaa.operator (bb).operator (bb)operator (aa,bb)
11、operator (aa,bb)二元运算符函数二元运算符函数 operator 所需的一个操作数由对象所需的一个操作数由对象 aaaa通过通过 this this 指针隐含地传递。因此它只有一个参数。这时,运算符指针隐含地传递。因此它只有一个参数。这时,运算符函数用类的函数用类的 成员函数成员函数 表示。表示。二元运算符函数二元运算符函数 operator 所需的两个操作数在参数表中所需的两个操作数在参数表中由对象由对象 aa aa 和和 bbbb显式地提供,适用于没有显式地提供,适用于没有thisthis指针的情况。这时,指针的情况。这时,运算符函数用类的运算符函数用类的 友员函数友员函数
12、表示表示13ShenyangAerospaceUniversity用成员函数重载运算符例例1 1:将:将“+”、“-”运算重载为复数类的运算重载为复数类的成员函数。成员函数。规则规则:实部和虚部分别相加减。实部和虚部分别相加减。操作数操作数:两个操作数都是复数类的对象。两个操作数都是复数类的对象。14ShenyangAerospaceUniversity#includeusing namespace std;class Complex/复数类声明public:/外部接口Complex(double r=0.0,double i=0.0)real=r;imag=i;/构造函数Complex op
13、erator+(Complex c2);/+重载为成员函数Complex operator-(Complex c2);/-重载为成员函数void display();/输出复数private:/私有数据成员double real;/复数实部double imag;/复数虚部;15ShenyangAerospaceUniversity/运算符重载函数实现Complex Complex:operator+(Complex c2)Complex c;c.real=c2.real+real;c.imag=c2.imag+imag;return Complex(c.real,c.imag);Comple
14、x Complex:operator-(Complex c2)Complex c;c.real=c2.real-real;c.imag=c2.imag-imag;return Complex(c.real,c.imag);16ShenyangAerospaceUniversityvoidComplex:display()cout(real,imag)endl;voidmain()/主函数主函数 Complexc1(5,4),c2(2,10),c3;/声明复数类的对象声明复数类的对象coutc1=;c1.display();coutc2=;c2.display();c3=c1-c2;/使用重载运
15、算符完成复数减法使用重载运算符完成复数减法coutc3=c1-c2=;c3.display();c3=c1+c2;/使用重载运算符完成复数加法使用重载运算符完成复数加法coutc3=c1+c2=;c3.display();c1=(5,4)c2=(2,10)c3=c1-c2=(3,-6)c3=c1+c2=(7,14)17ShenyangAerospaceUniversity一元运算符一元运算符一元运算符,不论是一元运算符,不论是前置前置还是还是后置后置,都需要一个操作数:,都需要一个操作数:obj及及obj可以解释为:可以解释为:objobj.operator ().operator ()ope
16、rator (operator (objobj)一元运算符函数一元运算符函数 operator 所需的一个操作数由对象所需的一个操作数由对象 objobj通过通过this this 指针隐含地传递,因此参数表为空。这时,运算符函指针隐含地传递,因此参数表为空。这时,运算符函数用类的数用类的 成员函数成员函数 表示。表示。一元运算符函数一元运算符函数 operator 所需的一个操作数在参数表中所需的一个操作数在参数表中由对象显式地提供,适用于没有由对象显式地提供,适用于没有thisthis指针的情况。这时,运算符指针的情况。这时,运算符函数用类的函数用类的 友员函数友员函数 表示。表示。18S
17、henyangAerospaceUniversity例例2.2.将运算符前置将运算符前置+(例如(例如 +i+i)和后置)和后置+(例如(例如i+i+)重载为时钟类的)重载为时钟类的成员函数成员函数。说明说明 前置单目运算符,重载函数没有形参,后置单前置单目运算符,重载函数没有形参,后置单目运算符,重载函数需要有一个整型形参。目运算符,重载函数需要有一个整型形参。操作数是时钟类的对象。操作数是时钟类的对象。实现时间增加实现时间增加1 1秒钟。秒钟。19ShenyangAerospaceUniversity#includeusing namespace std;class Clock/时钟类声明
18、public:/外部接口Clock(int NewH=0,int NewM=0,int NewS=0);void operator+();/前置一元运算符重载void operator+(int);/后置一元运算符重载private:/私有数据成员int Hour,Minute,Second;20ShenyangAerospaceUniversityvoid Clock:operator+()/前置一元运算符重载函数 Second+;if(Second=60)Second=Second-60;Minute+;if(Minute=60)Minute=Minute-60;Hour+;Hour=Ho
19、ur%24;cout+Clock:“Hour“:”Minute“:”Seconde;21ShenyangAerospaceUniversityvoid Clock:operator+(int)/后置一元运算符重载 coutClock+:“Hour“:”Minute“:”=60)Second=Second-60;Minute+;if(Minute=60)Minute=Minute-60;Hour+;Hour=Hour%24;22ShenyangAerospaceUniversity/其它成员函数的实现略void main()Clock myClock(23,59,59);myClock+;/运算
20、符后置+myClock;/运算符前置Clock+:23:59:59+Clock:0:0:123ShenyangAerospaceUniversity有时候,用成员函数重载运算符会碰到麻烦。有时候,用成员函数重载运算符会碰到麻烦。例如:例如:classComplexintReal;intImag;public:Complex(int a)Real=a;Imag=0;Complex(inta,intb)Real=a;Imag=b;Complex operator+(Complex);.;intmain()Complexz(2,3),k(3,4);z=z+27;/okz=27+z;/error.表达
21、式 z+27 可被解释为z.operator+(27)z 是复数对象,使用“+”的 重载版本;由于重载算符函数要求的 右操作数也为复数,系统通过 构造函数 Complex(int a)将 整数 27 转换为 Complex 类常 量Complex(27)表达式表达式27+z可被解释为可被解释为27.operator+(z)该式子毫无意义。该式子毫无意义。27不是不是Complex类对象,类对象,不能调用算符重载函数与对象不能调用算符重载函数与对象z相加相加!此时,成员函数重载的算此时,成员函数重载的算符符“+”不支持交换律。不支持交换律。24ShenyangAerospaceUniversit
22、y用友元重载运算符采用友元运算符的时机采用友元运算符的时机:在第一个参数需要隐式转换的情形下,使用友在第一个参数需要隐式转换的情形下,使用友员函数重载算符是正确的选择。员函数重载算符是正确的选择。原因原因:由于友员函数没有隐含由于友员函数没有隐含 thisthis 指针,用友员函指针,用友员函数重载算符时,所需操作数都必须在参数表显数重载算符时,所需操作数都必须在参数表显式声明,所以很容易实现类型的隐式转换。式声明,所以很容易实现类型的隐式转换。25ShenyangAerospaceUniversity例3.将+、-(二元运算符)重载为复数类的友元函数。说明:两个操作数都是复数类的对象。26S
23、henyangAerospaceUniversity#includeusingnamespacestd;classcomplexpublic:complex(doubler=0.0,doublei=0.0)/构造函数构造函数real=r;imag=i;friendcomplexoperator+(complexc1,complexc2);/运算符运算符+重载为友元函数重载为友元函数friendcomplexoperator-(complexc1,complexc2);/运算符运算符-重载为友元函数重载为友元函数voiddisplay();private:doublereal;doubleima
24、g;27ShenyangAerospaceUniversitycomplexoperator+(complexc1,complexc2)/运算符重载友元函数实现运算符重载友元函数实现returncomplex(c2.real+c1.real,c2.imag+c1.imag);complexoperator-(complexc1,complexc2)/运算符重载友元函数实现运算符重载友元函数实现returncomplex(c1.real-c2.real,c1.imag-c2.imag);/其它函数和主函数同例其它函数和主函数同例1 128ShenyangAerospaceUniversity使用
25、友员运算符重载的问题首先看一个三维坐标点类的设计,例首先看一个三维坐标点类的设计,例4 4:classPoint3DclassPoint3Dprivate:private:intintx,y,z;x,y,z;public:public:Point3DPoint3Doperator+(operator+(Point3DPoint3D&t);&t);/重载重载“+”Point3DPoint3Doperator+();operator+();/重载重载“+”voidshow();voidshow();voidvoidassign(intassign(int mxmx,intintmy,my,inti
26、nt mzmz););29ShenyangAerospaceUniversityPoint3DPoint3DPoint3DPoint3D:operator+(:operator+(Point3DPoint3D&t)t)Point3DPoint3Dtemp;temp;temp.x=x+t.x;temp.y=y+t.y;temp.z=z+t.z;temp.x=x+t.x;temp.y=y+t.y;temp.z=z+t.z;returntemp;returntemp;Point3DPoint3D Point3DPoint3D:operator+():operator+()x+;y+;z+;x+;y+
27、;z+;return*this;return*this;voidvoidPoint3DPoint3D:show():show()coutcoutx“,”y“,”z“n”;x“,”y“,”z x+;-x+;oplopl-y+;-y+;oplopl-z+;-z+;return return *oplopl;问题问题问题问题C+不知道如何激活该函数,下述代码无法编译:不知道如何激活该函数,下述代码无法编译:Point3D ob(1,2,3);&ob+;/error二义性二义性二义性二义性对对对对 obob的地址进行递加?还是的地址进行递加?还是的地址进行递加?还是的地址进行递加?还是将对象将对象将对
28、象将对象 obob递加?递加?递加?递加?33ShenyangAerospaceUniversity3.3.3.3.使用引用参数使用引用参数使用引用参数使用引用参数:Point3DPoint3DPoint3DPoint3D:operator+(:operator+(Point3D&Point3D&oplopl)oplopl.x+;.x+;oplopl.y+;.y+;oplopl.z+;.z+;returnreturnoplopl;下述代码是正确的:下述代码是正确的:Point3Dob(1,2,3);Point3Dob(1,2,3);+ob;+ob;/ok/ok34ShenyangAerospa
29、ceUniversity运算符重载说明q若一运算符的操作需要若一运算符的操作需要修改类对象状态修改类对象状态时,则时,则它它应该是成员函数应该是成员函数(如(如=,*=,+)。定义成友)。定义成友员时要用引用参数。员时要用引用参数。q如果运算符的操作数(尤其是第一个操作数)如果运算符的操作数(尤其是第一个操作数)希望有希望有隐式转换,则重载算符时必须隐式转换,则重载算符时必须用友员函数用友员函数q不能用友员函数重载的运算符是不能用友员函数重载的运算符是=()()35ShenyangAerospaceUniversity常见运算符重载举例1、重载赋值运算符(a=b)重载格式重载格式TypeTyp
30、e&Type:Type:operatoroperator=(constconst TypeType&from)from)/复制复制复制复制 type type type type 的成员的成员的成员的成员 36ShenyangAerospaceUniversityclassPoint3DclassPoint3D intintx,y,z;x,y,z;public:public:Point3DPoint3D&operator=(&operator=(Point3DPoint3D&t)&t);Point3DPoint3Doperator+();operator+();voidshow();voids
31、how();voidassign(voidassign(intint mxmx,intintmy,my,intint mzmz););Point3DPoint3D&Point3DPoint3D:operator=(:operator=(Point3DPoint3D&t)&t)x=t.x;y=t.y;z=t.z;x=t.x;y=t.y;z=t.z;return*this;return*this;/省略省略其它成员函数定义其它成员函数定义main()main()Point3DPoint3Da,b;a,b;a.assign(1,2,3);a.assign(1,2,3);b=a;b=a;b.show(
32、);b.show();37ShenyangAerospaceUniversity有关说明有关说明重载的运算符函数重载的运算符函数operator=必须是成员函数;必须是成员函数;如果用户没有为类重载赋值运算符函数,编辑程序将如果用户没有为类重载赋值运算符函数,编辑程序将生成一个缺省的赋值运算符;生成一个缺省的赋值运算符;拷贝函数用于创建一个新对象,赋值运算符是改变一拷贝函数用于创建一个新对象,赋值运算符是改变一个已存在的对象的值;个已存在的对象的值;使用缺省的赋值运算符。对于简单的类(使用缺省的赋值运算符。对于简单的类(Point3D),),缺省赋值函数工作得很好。但数据成员使用指针时会出缺省
33、赋值函数工作得很好。但数据成员使用指针时会出问题问题。38ShenyangAerospaceUniversity/考虑一个简单的类:考虑一个简单的类:考虑一个简单的类:考虑一个简单的类:classstringchar*p;intsize;string(intsz):size(sz)p=newcharsz;string()deletep;/使用该类的函数:使用该类的函数:使用该类的函数:使用该类的函数:voidmain()voidmain()strings1(10);strings1(10);strings2(10);strings2(10);s1=s2;s1=s2;s1.ps1.ps2.ps2
34、.p39ShenyangAerospaceUniversity/考虑一个简单的类:考虑一个简单的类:考虑一个简单的类:考虑一个简单的类:classstringchar*p;intsize;string(intsz):size(sz)p=newcharsz;string()deletep;/使用该类的函数:使用该类的函数:使用该类的函数:使用该类的函数:voidmain()voidmain()strings1(10);strings1(10);strings2(10);strings2(10);s1=s2;s1=s2;s2.ps2.ps1.ps1.p这块内存被封锁这块内存被封锁这块内存被封锁这块
35、内存被封锁不能使用不能使用不能使用不能使用两次调用析构函数两次调用析构函数两次调用析构函数两次调用析构函数这块内存被释放两次这块内存被释放两次这块内存被释放两次这块内存被释放两次40ShenyangAerospaceUniversity解决方法,重载解决方法,重载解决方法,重载解决方法,重载“=”运算符为新的语义:运算符为新的语义:运算符为新的语义:运算符为新的语义:structstructstringstringchar*p;char*p;intintsize;size;string(string(intint szsz)p=newcharsize=)p=newcharsize=szsz;s
36、tring()deletep;string()deletep;string&operator=(conststring&a);string&operator=(conststring&a);string&string:operator=(conststring&a)string&string:operator=(conststring&a)if(this=&a)return*this;if(this=&a)return*this;/防止防止 s1=s2s1=s2deletep;deletep;/释放释放 s1 s1 对象指向的内存空间对象指向的内存空间 p=newcharsize=a.size
37、;p=newcharsize=a.size;/重新分配重新分配 s1 s1 的空间的空间 strcpystrcpy(p,a.p);return*this;(p,a.p);return*this;41ShenyangAerospaceUniversity&TomJohnS1.pS2.p&TomJohnS1.pJohn新建存储区新建存储区拷贝串拷贝串&S2.p释放空间释放空间内存空间变化情况p=newcharsize=a.size;strcpy(p,a.p);42ShenyangAerospaceUniversity2、重载下标运算符、重载下标运算符 intmain()intarr10;arr10
38、=0;inttmp=arr10;return0;设设x是类是类X的一个对象,则表达式的一个对象,则表达式xy可被解释为可被解释为x.operator(y)重载时,只能显式地声明一个参数重载时,只能显式地声明一个参数43ShenyangAerospaceUniversity下面的类下面的类Vector中定义了一个私有的数组成员,要想访问数组中的某个元素,中定义了一个私有的数组成员,要想访问数组中的某个元素,习惯上是使用下标比较直观(如习惯上是使用下标比较直观(如Vector4),但由于类的封装性,但由于类的封装性,不可能访问到这样的细节。可以通过重载下标运算符不可能访问到这样的细节。可以通过重载
39、下标运算符来实现。来实现。/file Vector.h#ifndef VECTOR_H#define VECTOR_H#include using namespace std;class VectorVectorint length;int*arr;public:VectorVector(int len);VectorVector();void Print();void Add(int value);/返回当前下标所指数组元素返回当前下标所指数组元素int&operator(int n);#endif/file Vector.cpp#include VectorVector.hVectorVe
40、ctor:VectorVector(int len)arr=new intlen;if(arr=NULL)exit(1);length=0;VectorVector:VectorVector()if(arr!=NULL)delete arr;arr=NULL;void VectorVector:Print()coutn数组元素数组元素:;for(int i=0;ilength;i+)coutarri;44ShenyangAerospaceUniversityvoid VectorVector:Add(int value)arrlength+=value;int&VectorVector:ope
41、rator(int n)return arrn;/file Main.cpp#include VectorVector.hvoid main()VectorVector vectorvector(5);cout请连续输入请连续输入5个整数个整数n;int tempvalue;for(int i=0;itempvalue;vectorvector.Add(tempvalue);vectorvector.Print();vectorvector3=50;coutn修改后的修改后的和输出运算符”可以实现实现用户自定义类型的输入输出可以实现实现用户自定义类型的输入输出/file Complex.h#i
42、fndef COMPLEX_H#define COMPLEX _H#include using namespace std;class Complexfloat real,imag;public:Complex(float r,float i)real=r;imag=i;Complex()real=0;imag=0;friend ostream&operator(istream&,Complex&);#endif46ShenyangAerospaceUniversity/file Complex.cpp#include Complex.hostream&operator(ostream&out
43、put,Complex&obj)output0)output+;else if(obj.image0)output“-”if(obj.imag!=0)outputobj.imagi;output(istream&input,Complex&obj)coutobj.real;inputobj.imag;return input;47ShenyangAerospaceUniversity/file Main.cpp#include ComplexComplex.hvoid main()Complex c1(2.3f,4.6f),c2(3.6f,-9.8f),c3,c4;coutc1、c2的值分别是的值分别是:endl;coutc1c3c4;/等价于等价于?coutc3、c4的值分别是的值分别是:endl;coutc3c4;operator(operator(operator(cin,c1),c2);c1、c2的值分别是的值分别是:2.3+4.6i3.6-9.8iInput the real,imag of the complex:2 3Input the real,imag of the complex:5 6c3、c4的值分别是的值分别是:2+3i5+6i48ShenyangAerospaceUniversity本节作业本节作业P298 8-1、8-9P299 8-749
限制150内