第四章运算符重载.ppt

上传人:本田雅阁 文档编号:2097041 上传时间:2019-02-13 格式:PPT 页数:81 大小:455.51KB
返回 下载 相关 举报
第四章运算符重载.ppt_第1页
第1页 / 共81页
第四章运算符重载.ppt_第2页
第2页 / 共81页
第四章运算符重载.ppt_第3页
第3页 / 共81页
亲,该文档总共81页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《第四章运算符重载.ppt》由会员分享,可在线阅读,更多相关《第四章运算符重载.ppt(81页珍藏版)》请在三一文库上搜索。

1、第四章 运算符重载,4.1什么是运算符重载 4.2运算符重载的方法 4.3重载运算符的规则 4.4运算符重载函数作为类成员函数和友元函数 4.5重载双目运算符 4.6重载单目运算符 4.7重载流插入运算符和流提取运算符 4.8不同类型数据间的转换,4.1什么是运算符重载,C+ 为程序员提供了灵活的手段,让程序员自己定义类,自己设计相应的运算符(必须在已有的运算符基础上设计),使之应用于自己定义的类。与函数重载类似,对已有的运算符赋予新的含义,用一个运算符表示不同功能的运算,这就是运算符重载。 实际上,我们在此之前已经使用了运算符重载。如是C+的移位运算符,它又与流对象cout配合作为流插入运算

2、符,这是C+对进行了重载处理。,运算符重载的实质,运算符重载是对已有的运算符赋予多重含义。 必要性 C+中预定义的运算符其运算对象只能是基本数据类型,而不适用于用户自定义类型(如类) 实现机制 将指定的运算表达式转化为对运算符函数的调用,运算对象转化为运算符函数的实参。 编译系统对重载运算符的选择,遵循函数重载的选择原则。,例4.1 通过成员函数实现复数的加法。 class Complex private: double real; double imag; public: Complex()real=0;imag=0; Complex(double r,double i)real=r;ima

3、g=i; Complex complex_add(Complex ,Complex Complex:complex_add(Complex ,在Complex类中定义了complex_add函数做加法,函数的参数是引用对象,作为一个加数。在函数里定义了临时对象c,两个赋值语句相当于: c.real = this-real +c2.real; c.imag = this-imag+c2.imag; 在main函数中通过对象c1调用加法函数,上面的语句相当于: c.real = c1.real +c2.real; c.imag = c1.imag+c2.imag; 能否用+运算符实现复数加法?,4

4、.2运算符重载的方法,运算符重载的方法是定义一个重载运算符函数,在需要时系统自动调用该函数,完成相应的运算。运算符重载实质上是函数的重载。运算符重载函数的格式是: 数据类型 operator 运算符(形参表) 重载处理 数据类型:是重载函数值的数据类型。 operator 是保留字,规则和限制,C+中可以重载除下列运算符外的所有运算符: . .* : ?: sizeof() 只能重载C+语言中已有的运算符,不可臆造新的。 不改变原运算符的优先级和结合性。 不能改变操作数个数。 经重载的运算符,其操作数中至少应该有一个是自定义类型。,两种形式,重载为类成员函数。 重载为友元函数。,运算符函数,声

5、明形式 函数类型 operator 运算符(形参) 重载为类成员函数时 参数个数=原操作数个数-1 (后置+、-除外) 重载为友元函数时 参数个数=原操作数个数,且至少应该有一个自定义类型的形参。,不能重载的运算符只有5个: . 成员运算符 .* 成员指针运算符 : 域运算符 sizeof 长度运算符 ?: 条件运算符 重载函数名是由operator和运算符联合组成。 复数加法运算符重载函数原型可以是: Complex operator+ (Complex 例4.2 重载运算符+,用于两个复数相加。,分析:定义一个复数类,用成员函数实现加号的重载函数。两个复数相加结果仍是复数,所以函数的返回值

6、的类型也是复数类。用成员函数实现运算符重载函数时,调用格式是“对象名.成员名”,此时对象就是一个参与运算的操作数,加法还需要另一个操作数,这个操作数用函数的参数传递,参数的类型就是复数类。而运算结果用函数值返回。,class Complex public: Complex()real=0;imag=0; Complex(double r,double i)real=r;imag=i; Complex operator + (Complex ,Complex Complex:operator + (Complex ,int main() Complex c1(3,4),c2(5,-10),c3;

7、 c3=c1+c2; cout“c1=“;c1.display(); cout“c2=“;c2.display(); cout“c1+c2=“;c3.display(); return 0; ,说明: (1)用运算符重载函数取代了例 4.1中的加法成员函数,从外观上看函数体和函数返回值都是相同的。 (2)在主函数中的表达式c3=c2+c1 取代了例4.1中的c3=plex_add(c2) ,编译系统将表达式c3=c1+c2 解释为 c1.operator + ( c2 ) 对象c1调用的重载函数operator + ,以c2为实参计算两个复数之和。,请考虑在例4.2中能否用一个常量和一个复数相

8、加?如 c3 = 3 + c2; / 错误 应该定义对象:Complex C1(3.0,0) : c3 = C1 + c2; 注意:运算符重载后,其原来的功能仍然保留,编译系统根据运算表达式的上下文决定是否调用运算符重载函数。 运算符重载和类结合起来,可以在C+ 中定义使用方便的新数据类型。,4.3重载运算符的规则,(1)C+只允许已有的部分运算符实施重载。 (2)不能重载的运算符有五个。 (3)重载不改变操作数的个数。 (4)重载不改变运算符的优先级。 (5)运算符重载函数不能带默认值参数。 (6)运算符重载函数必须与自定义类型的对象联合使用,其参数至少有一个类对象或类对象引用。 (7)C+

9、默认提供 = 和 & 运算符重载。,(8)运算符重载函数可以是类成员函数也可以是类的友元函数,还可以是普通函数。 (9)C+规定赋值运算符、下标运算符、函数调用运算符必须定义为类的成员函数;而输出流插入、输入流提取、类型转换运算符不能定义为类的成员函数。,4.4运算符重载函数作为类成员函数和友元函数,在例4.2程序中对运算符+进行了重载,该例将运算符重载函数定义为复数类的成员函数。 从该程序中看到运算符重载为成员函数时,带一个类类型的形参,而另一个加数就是对象自己。 例4.3 将加法运算符重载为适用于复数加法,重载函数作为类的友元函数。,#include class Complex publi

10、c: Complex () real=0;imag=0; Complex (double r) real=r;imag=0; Complex (double r,double i) real=r;imag=i; friend Complex operator+ (Complex ,Complex operator+ (Complex ,int main() Complex c1(3,4),c2(5,-10),c3; c3=c1+c2; cout“c1=“; c1.display(); cout“c2=“; c2.display(); cout“c1+c2=“; c3.display(); re

11、turn 0; ,加法运算符重载为友元函数,C+ 在编译时将表达式c1+c2解释为 operator + ( c1, c2) 即相当于执行以下函数 Complex operator + ( Complex 因为普通函数是不能直接访问对象的私有成员,如果普通函数必须访问对象的私有成员,可调用类的公有成员函数访问对象的私有成员。这会降低效率。,书上的错误,如想将一个复数和一个整数相加,运算符重载函数作为成员函数定义如下: Complex Complex :operator + ( int 注意在运算符+的左侧必须是Complex类对象,程序中可以写成: c3 = c2 + n 不能写成: c3 =

12、 n + c2,书上的错误,如果要求在使用重载运算符时,运算符左侧操作数不是对象,就不能使用前面定义的运算符重载函数,可以将运算符重载函数定义为友元函数: friend Complex operator + ( int 友元函数不要求第一个参数必须是类类型,但是要求实参要与形参一一对应: c3 = n + c2 / 顺序正确 c3 = c2 +n / 顺序错误,为了实现加法的交换率,必须定义两个运算符重载函数,记住成员函数要求运算符左侧的操作数必须是自定义类型的对象,而友元函数没有这个限制,可以用下面两个组合中任意一个: (1)成员函数(左操作数是对象,右操作数是非对象)、友元函数(左操作数是

13、非对象,右操作数是对象) (2)友元函数(左操作数是对象,右操作数是非对象)、友元函数(左操作数是非对象,右操作数是对象),由于使用友元会破坏类的封装,要尽量将运算符重载函数定义为成员函数。但考虑到各方面的因素,一般将单目运算符重载为成员函数,将双目运算符重载为友元函数。 VC+6.0的不带后缀h的头文件不支持把成员函数重载为友元函数。但VC+6.0带后缀h的头文件支持这项功能,所以要将程序中的语句: #include using namespace std; 改成: #include 即可正常运行。,4.5重载双目运算符,双目的意思是运算符左边和右边的操作数均参加运算。 如果要重载 B 为类

14、成员函数,使之能够实现表达式 oprd1 B oprd2,其中 oprd1 为A 类对象,则 B 应被重载为 A 类的成员函数,形参类型应该是 oprd2 所属的类型。 经重载后,表达式 oprd1 B oprd2 相当于 oprd1.operator B(oprd2)。,例4.4 定义一个字符串类String,用来处理不定长的字符串,重载相等、大于、小于关系运算符,用于两个字符串的等于、大于、小于的比较运算。 操作数:两个操作数都是字符串类的对象。 规则:两个字符串进行比较。 将“”运算重载为字符串类的成员函数。,(1)先建立一个String类 #include #include class

15、 String / String 是用户自己指定的类名 public: String() p=NULL; String( char *str ) ; void display(); private: char *p; ;,String:String(char *str) p=str; void String:display() coutp; int main() String string1(“Hello“),string2(“Book“); string1.display(); coutendl; string2.display(); return 0; ,先编写出简单的程序框架,编写和调试

16、都比较方便。构造函数是把定义对象时的实参的地址赋予数据成员p,p是指向实参的指针。程序实现了建立对象、输出字符串对象的功能。程序运行结果分别输出 Hello Book (2)有了这个基础后,再增加所需的其他内容,先重载大于运算符。程序如下:,/本程序适用于VC+ 6.0 #include #include class String public: String () p=NULL; String (char *str); void display(); friend bool operator(String ,void String:display() cout(String ,运算符重载函数

17、定义为友元函数,函数值是布尔类型,在函数中调用了strcmp库函数,string1.p指向“Hello”,string2.p指向“Book”,程序运行结果是1。 (3)扩展到对三个运算符重载 在String类体中声明三个重载函数是友元函数,并编写相应的函数。,/本程序适用于VC+ 6.0 #include #include class String public: String()p=NULL; String(char *str); friend bool operator (String ,String:String(char *str) p=str; void String:display

18、() cout(String ,bool operator(String ,int main() String string1(“Hello“),string2(“Book“),string3(“Computer“); coutstring2)endl; cout(string1string3)endl; cout(string1=string2)endl; return 0; 运行结果为 1 0 0,4.6重载单目运算符,单目运行符只要一个操作数,由于只有一个操作数,重载函数最多只有一个参数,如果将运算符重载函数定义为成员函数还可以不用参数。 下面以自增运算符+为例,学习单目运算符的重载函数

19、的编写方法。 例4.5 有一个Time类,数据成员有时、分、秒。要求模拟秒表,每次走一秒,满60秒进位,秒又从零开始计数。满60分进位,分又从零开始计数。输出时、分和秒的值。,#include using namespace std; class Time public: Time()hour=0;minute=0;sec=0; Time(int h,int m,int s):hour(h),minute(m),sec(s) Time operator+(); void display()couthour“:“minute“:“secendl; private: int hour; int m

20、inute; int sec; ;,Time Time:operator +() /前置单目运算符重载函数 sec+; if(sec=60) sec=sec-60; minute+; if(minute=60) minute=minute-60; hour+; hour=hour%24; return *this; ,43,int main() Time time1(23,59,0); for (int i=0;i61;i+) + time1; time1.display(); return 0; ,C+中除了有前+外,还有后+。同样的运算符由于操作数的位置不同,含义也不同。怎样区分前+和后+

21、?C+给了一个方法,在自增或自减运算符重载函数中,增加一个int 形参。程序员可以选择带int形参的函数做后+,也可以选择不带int形参的函数做前+。 例4.6 在例4.5 的基础上增加后+运算符重载函数。,#include using namespace std; class Time public: Time()hour=0;minute=0;sec=0; Time(int h, int m,int s):hour(h),minute(m),sec(s) Time operator+(); Time operator+(int); void display()couthour“:“minu

22、te“:“secendl; private: int hour ; int minute; int sec; ;,Time Time : operator +() /前置单目运算符重载函数 sec+; if(sec=60) sec=sec-60; minute+; if(minute=60) minute=minute-60; hour+; hour=hour%24; return *this; ,47,分析:后+运算的含义是操作数先参加其他运算后再自加。如 m=n+ 先将n的值赋予m,然后n再自加1。设计后+重载函数要遵循这个特性。 Time Time:operator+(int) Time

23、 temp(*this); / 保存修改前的对象做返回值 +(*this); return temp; ,int main() Time time1(21,34,59),time2; cout“ time1 : “; time1.display(); +time1; cout“+time1: “; time1.display(); time2 = time1+; cout“time1+: “; time1.display(); cout“ time2 : “; time2.display(); return 0; ,程序运行结果如下: Time1: 21:34:59 +Time1: 21:35

24、:0 Time1+: 21:35:1 Time2: 21:35:0,4.7重载流插入运算符和流提取运算符,cin和cout分别是istream类和ostream类的对象。 C+已经对和 using namespace std;把头文件包含到程序中。 用户自定义类型的数据不能直接用输出和输入,如想用它们进行输入或输出,程序员必须对它们重载。,重载函数原型的格式如下: istream 从格式上看,重载函数和重载函数只能定义为友元函数,不能定义为成员函数,因为函数有两个形参,并且第一个形参不是自定义类型。,4.7.1重载流插入运算符“”,例4.7 在例4.2的基础上用重载函数输出复数。 分析:在类中

25、声明重载函数是友元函数 friend ostream ,/本程序适用于VC+ 6.0 #include int main() Complex c1(2,4),c2(6,10),c3; c3=c1+c2; coutc3; return 0; ,分析C+怎样处理”cout c3;”语句 运算符的左边是ostream的对象cout,右边是程序员自定义类complex的对象c3,语句符合运算符重载友元函数operator的形参类型要求,系统调用友元函数,C+把这个语句解释为: operator ( cout , c3); 通过形参引用传递,函数中的output就是cout,函数中的c就是c3,函数就变

26、成: cout“(“c3.real“+“c3.imag“i)“endl; return cout; ,return cout 是将输出流现状返回。C+ 规定运算符重载函数第一个参数和函数的类型必须是 ostream 类型的引用,目的是为了返回cout的当前值,以便连续输出。,4.7.2重载流提取运算符“”,例4.8 在例4.7 的基础上增加流提取运算符重载函数,用cin输入复数,用cout (istream ,int main() Complex c1,c2; cinc1c2; cout重载函数中的形参input是istream类对象引用,在执行cinc1时,调用operator函数,将cin

27、引用传递给input,input是cin的别名,同样c是c1的别名。因此,input c.real c.imag;相当于cin c1.real c1.imag。函数返回cin的新值。使程序可以用重载函数连续从输入流提取数据给complex类对象。,程序逻辑上是正确的,但还有缺陷,如果输入的虚部是负数时,输出的形式变成: c2 = ( 4+ - 10i ) 在负数前多个正号。可以对程序稍做修改: ostream ,从本章例子中可以注意到,在运算符重载中使用引用参数的重要性,用引用形参在调用函数时,通过传递地址方式让形参成为实参的别名,不用生成临时变量,减少了时间和空间的开销。此外,如重载函数的返

28、回值是对象引用时,返回的是对象,它可以出现在赋值号的左侧而成为左值,可以被赋值或参与其他操作(如保留 cout流的当前值以便能连续使用输出)。,4.8.1标准类型数据间的转换,int i = 6; i = 7.5 + i; 编译过程: 7.5作为double型数处理 求解表达式时,将6转换陈double,然后再和7.5相加 得到的13.5的值向整型变量i赋值时,先转换为13再赋值 这种转换是c+编译系统自动完成的,称为隐式类型转换。,C+的显式类型转换,是一种人为的强制转换。 格式: 类型名(数据) 例如:int(89.5) C语言中的采用形式 (类型名)数据 如: (int)89.5 C+保

29、留了c语言的用法,提倡用c+的方法,4.8.2用转换构造函数进行类型转换,作用:将一个其它类型的数据转换成一个指定的类的对象。 转换构造函数只有一个形参,如 Complex(double r)real=r;imag=0; 其作用就是将double型的参数r转换成Complex类的对象 Complex c1(3.5);/建立一个对象,调用构造函数 可以用声明语句建立一个无名的Complex对象,如 Complex(3.6)/合法,但无法使用 可以在一个表达式中使用无名对象,如 c1=complex(3.6);/假设c1已被定义为Complex类的对象,转换构造函数也是一种构造函数,它遵循构造函数

30、的一般规则。 通常把有一个参数的构造函数用作类型转换,所以,称为转换构造函数。 注意: 转换构造函数只能有一个参数。如果有多个参数,就不是转换构造函数。原因是:如果有多个参数的话,究竟是把哪个参数转换成类的对象呢,使用转换构造函数将一个指定的数据转换成类的对象的方法如下: (1)先声明一个类(如上面的Complex)。 (2)在这个类中定义一个只有一个参数的构造函数,参数的类型是需要转换的类型,在函数体中指定转换的方法。 (3)在该类的作用域内可以用以下形式进行类型转换: 类名(指定类型的数据),不仅可以将一个标准类型数据转换成类对象,也可以将另一个类的对象转换成转换构造函数所在类的对象。 如

31、:可以将一个学生类对象转换成教师类对象,可以在Teacher类中写出下面的构造函数: Teacher(Student 注意: 对象s中的num, name, sex必须是公有成员,否则不能被类外引用。,4.8.3用类型转换函数进行类型转换,作用:将一个类的对象转换成另一个类型的数据 格式: operator 类型名()实现转换的语句 在函数名前面不能指定函数类型,函数没有参数 返回值的类型是由函数名中指定的类型名来确定的。类型转换函数只能作为成员函数,因为转换的主体是本类的对象。不能作为友元函数或普通函数。,转换构造函数和类型转换运算符的共同功能: 当需要的时候,编译系统会自动调用这些函数,建

32、立一个无名的临时对象(或临时变量) 例: double d1,d2; Complex c1,c2; 假设类中定义了类型转换函数 对于表达式:d1=d2+c1;,编译系统发现“+”左侧的d2是double型,而右侧的c1是Complex类对象,如果没有对运算符“+”进行重载,就会检查有无类型转换函数,结果发现有对double的重载函数,就调用该函数,把Complex类对象c1转换为double型数据,建立一个临时的double变量,并与d2相加,最后将一个double型数据赋给d1。,如果类中已定义转换构造函数并重载了运算符“+”(作为Complex类的友元函数),但未对double定义类型转换

33、函数(或者说未对double重载)对于表达式: c2=c1+d2; 编译系统怎样处理呢?,它发现运算符“+”左侧的c1是Complex类对象,右侧的d2是double型。 编译系统寻找有无对“+”的重载,发现有operator+函数,但它是Complex类的友元函数,要求两个Complex类的形参,即只能实现两个Complex类对象相加,而现在d2是double型,不合要求。 在类中没有对double进行重载,因此不可能把c1转换为double型数据然后相加。 编译系统就去找有无转换构造函数,发现有,就调用转换构造函数Complex(d2),建立一个临时的Complex类对象,在调用opera

34、tor+函数,将两个复数相加,然后赋给c2。 相当于执行表达式:c2=c1+ Complex(d2),例4.9 使用类型转换函数的简单例子 #include using namespace std; class Complex public: Complex()real=0;imag=0; Complex(double r,double i)real=r;imag=i; operator double() return real; private: double real; double imag; ; int main() Complex c1(3,4),c2(5,-10),c3; doub

35、le d; d=2.5+c1; coutdendl; return 0; ,5.5,分析: (1)如果在Complex类中没有定义类型转换函数operator double,程序编译将会出错。因为不能实现double数据类型与Complex类对象的相加。 (2)如果在main函数中加一语句:c3=c2;编译系统是把c2按Complex类对象处理,因为赋值号两侧为同一类数据,可以合法赋值。 (3)如果在Complex类中声明了重载运算符“+”函数作为友元函数,并在类外定义operator+函数: Complex operator+( Complex c1, Complex c2) return

36、Complex(c1.real+c2.real,c1.imag+c2.imag); c3=c1+c2;/有运算符“+”重载,可以实现对象相加 d=c1+c2;/先相加,再通过对double的重载函数将临时对象转化为double,再赋值,对类型的重载和对运算符的重载的概念和方法相似 重载函数都使用关键字operator,它的意思是“运算符”。因此,通常把类型转换函数也成为类型转换运算符函数 由于它也是重载函数,因此也称为类型转换运算符重载函数(或称强制类型转换运算符重载函数),例4.10包含转换构造函数、运算符重载函数和类型转换函数的程序 #include using namespace std

37、; class Complex public: Complex()real=0;imag=0; Complex(double r)real=r;imag=0; Complex(double r,double i)real=r;imag=i; friend Complex operator + (Complex c1,Complex c2); void display(); private: double real; double imag; ;,Complex operator + (Complex c1,Complex c2) return Complex(c1.real+c2.real,

38、c1.imag+c2.imag); void Complex:display() cout“(“real“+“imag“i)“endl;,int main() Complex c1(3,4),c2(5,-10),c3; c3=c1+2.5; c3.display(); return 0; ,分析: (1)如果没有转换构造函数,则此程序编译出错,因为没有重载运算符使之能将Complex类对象与double数据相加。 (2)由于重载了运算符“+”,表达式c1+2.5,编译系统解释为: operator+(c1,2.5)/2.5不是Complex类对象 调用转换构造函数Complex(2.5),形成

39、表达式: operator+(c1,Complex(2.5),(3)如果把“c3=c1+2.5”改为“c3=2.5+c1”。编译仍能通过。我们从中得到结论:在已定义了相应的转换构造函数情况下,将运算符“+”函数重载为友元函数,在进行两个复数相加时,可以使用交换律。 如果运算符“+”重载函数不作为Complex类的友元函数,而作为Complex类的成员函数,不能满足交换律。 函数的原型: operator + (Complex c2);/Complex类成员函数 函数第一个参数省略了,它隐含指this所指的对象。 对于表达式:c1+2.5 c+编译系统解释为:c1.operator+(2.5),

40、通过转换构造函数Complex(2.5),建立一个临时的Complex对象。则表达式相当于:c1.operator+(Complex(2.5). 但对于表达式:2.5+c1。 C+系统解释为(2.5).operator+(c1)/错误,如果运算符函数重载为成员函数,它的第一个参数必须是本类的对象。当第一个操作数不是类对象时,不能将运算符函数重载为成员函数。如果将运算符“+”函数重载为成员函数,交换律不适用。 一般情况下,将双目运算符函数重载为友元函数。单目运算符则为重载成员函数。,(4)在上面的基础上增加类型转换函数: Complex类的公有部分为: public: Complex()real

41、=0;imag=0; Complex(double r)real=r;imag=0; Complex(double r,double i)real=r;imag=i; operator double()coutreturn real; friend Complex operator + (Complex c1,Complex c2); void display();,程序在编译时出错,原因是出现二义性。在处理c1+2.5时出现二义性。一种理解是:调用转换构造函数,把2.5变成Complex类对象,然后调用运算符“+”重载函数,与c1进行复数相加。 另一种理解是:把c1转换成double型数,然后与2.5进行相加。系统无法判定,这两者是矛盾的。 如果要使用类型转换函数,就应当删去运算符“+”重载函数。,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1