《程序设计实习》课程(C++ProgrammingPractice)程序设计实习第十五讲运算符重载主讲教师:田永鸿yhtian@pku.edu.cn://idm.pku.edu.cn/jiaoxue-CPP/cpp08.htm2008年4月21日北京大学《程序设计实习》课程2回顾:类和对象类的定义、成员属性、成员函数、类的作用域对象的创建、存储、访问构造函数、析构函数定义、调用时机特殊的构造函数:复制构造函数、转换构造函数、初始化列表类的特殊成员:static成员、const成员、引用成员const对象成员对象和封闭类友元this指针北京大学《程序设计实习》课程3课堂问题1.指出下列各题中的错误,并说明如何改正void~Time(int);classTime{private:inthour=12;intminute=0,second=0;}intTime(intnHour,intnMin,intnSec);2.以下关于this指针的说法中不正确的是:A.const成员函数内部不可以使用this指针B.成员函数内的this指针,指向成员函数所作用的对象。C.在构造函数内部可以使用this指针D.在析构函数内部可以使用this指针构造函数和析构函数不能有返回类型;成员属性不能在类定义时初始化const成员函数内部可以使用this指针:是一个const指针,不能改变this的地址及所指向的值北京大学《程序设计实习》课程4课堂问题3.指出下列题中的错误,并说明如何改正classX{X(inti,intj):base(i),rem(base%j){}intrem,base;}4.如下定义和申明中哪些是错误的,如何改正://example.hclassExample{public:staticdoublerate=6.5;staticconstintnSize=20;staticTimeTime(12,0,0);};//example.c#include“example.h”doubleExample::rate;TimeExample::Time;Base应在rem之前定义;或rem的初始化时不使用base,直接用i静态成员变量或成员对象不能在定义时初始化,应在.c程序中以全局变量的方式初始化;静态const类型则可以北京大学《程序设计实习》课程5课堂问题以下程序编译、连接都能通过,请写出运行时输出的结果。你认为没有输出的,就写无输出#includeiostreamusingnamespacestd;classSample{intA;staticintB;public:Sample(inta){A=a,B+=a;}staticvoidfunc(Samples);};voidSample::func(Samples){coutA=s.A,B=Bendl;}intSample::B=0;voidmain(){Samples1(2),s2(5);Sample::func(s1);Sample::func(s2);}静态成员函数的使用方法。其中的数据成员B是静态数据成员,求B之值是在构造函数中进行的。所以输出为:A=2,B=7A=5,B=7北京大学《程序设计实习》课程6内容提要抽象数据类型与运算符重载两种运算符重载的实现方式常见的运算符重载流运算符:、自增运算符++、自减运算符--抽象数据类型的强制类型转换示例程序作业北京大学《程序设计实习》课程7抽象数据类型与运算符重载C++预定义了一组运算符,用来表示对数据的运算+、-、*、/、%、^、&、~、!、|、=、、、!=、……只能用于基本的数据类型:整型、实型、字符型、逻辑型、……cin和cout使用运算符“”、“”进行流操作时,要求操作数是基本数据类型北京大学《程序设计实习》课程8C++提供了数据抽象的手段,允许用户定义抽象数据类型:类通过调用类的成员函数,对它的对象进行操作但是,在有些时候,用类的成员函数来操作对象时,很不方便。例如对一个群体,按照他们的体重指数进行排序:涉及不同对象中的“体重指数”成员属性在数学上,两个复数可以直接进行+、-等运算。但在C++中,直接将+或-用于复数是不允许的抽象数据类型与运算符重载北京大学《程序设计实习》课程9运算符重载我们希望:对一些抽象数据类型,也能够直接使用C++提供的运算符程序更简洁代码更容易理解例如boolcompareQuata=BillJimmyBill和Jimmy是CMan的两个对象比较他们的体重指数complex_a+complex_bcomplex_a和complex_b是两个复数对象求两个复数的和北京大学《程序设计实习》课程10对已有的运算符(C++中预定义的运算符)赋予多重的含义,使同一运算符作用于不同类型的数据时导致不同类型的行为目的是:扩展C++中提供的运算符的适用范围,以用于类所表示的抽象数据类型。同一个运算符,对不同类型的操作数,所发生的行为不同(5,10i)+(4,8i)=(9,18i)5+4=9运算符重载北京大学《程序设计实习》课程11classComplex{public:Complex(doubler=0.0,doublei=0.0){real=r;imaginary=i;}doublereal;//realpartdoubleimaginary;//imaginarypart};示例:复数类型定义北京大学《程序设计实习》课程12若能对+进行重新定义如下:Complexoperator+(constComplex&a,constComplex&b){returnComplex(a.real+b.real,a.imaginary+b.imaginary);}则可以Complexa(1,2),b(2,3),c;c=a+b;//等效于operator+(a,b);示例:复数类型定义北京大学《程序设计实习》课程13对类Complex重载运算符号“+”示例:复数的运算符重载classComplex{public:Complex(double=0.0,double=0.0);//constructorComplexoperator+(constComplex&)const;//additionComplexoperator-(constComplex&)const;//subtractionconstComplex&operator=(constComplex&);//assignmentprivate:doublereal;//realpartdoubleimaginary;//imaginarypart};问题:为什么使成员函数、参数及返回值为常数类型?//OverloadedadditionoperatorComplexComplex::operator+(constComplex&operand2)const{returnComplex(real+operand2.real,imaginary+operand2.imaginary);}//函数及参数定义为const,以使函数不能改变参数的值//OverloadedsubtractionoperatorComplexComplex::operator-(constComplex&operand2)const{returnComplex(real-operand2.real,imaginary-operand2.imaginary);}//Overloaded=operatorconstComplex&Complex::operator=(constComplex&right){real=right.real;imaginary=right.imaginary;return*this;//enablescascading}//函数的返回值定义为const,因为返回的是this指针Complexx,y(4.3,8.2),z(3.3,1.1);x=y+z;//y.operator+(z)//x.operator=(y.operator+(z))x=y-z;//x.operator=(y.operator-(z))北京大学《程序设计实习》课程16运算符重载实质是函数重载:在程序编译时把指定的运算表达式转换成对运算符函数的调用把运算的操作数转换成运算符函数的参数根据实参的类型决定调用哪个运算符函数C++中运算符重载的例子:“”和“”是用于移位的运算符,通过C++的标准类库分别被重载为流输入和流输出运算符北京大学《程序设计实习》课程17运算符重载:注意C++不允许定义新的运算符通过重载现有的运算符,使它在用于类的对象时具有新类型的含义重载后运算符的含义应该符合日常习惯complex_a+complex_bword_aword_bdate_b=date_a+n有时使用函数调用更好older(student_a,student_b)的语义比student_astudent_b更清晰:年龄大小、身材高矮、体型胖瘦、……重载不改变运算符的优先级、结合性、语法结构及参数个数以下运算符不能被重载:“.”、“.*”、“::”、“?:”、sizeof教材V2版p.340(V5版p.430)列出了可重载的运算符北京大学《程序设计实习》课程18运算符重载的形式重载为类的成员函数return_typeoperatoroperator_symbol(argument-list){function-body}重载为类的友员函数friendreturn_typeoperatorperator_symbol(argument-list){function-body}operator_symbol必须是C++中可以重载的运算符符号,例如“+”、“-”、……重载运算符“调用()、下标[]、成员访问-或者赋值运算符=”时,运算符重载函数必须声明为类的成员函数北京大学《程序设计实习》课程19运算符重载为成员函数return_typeoperatoroperator_symbol(argument-list){function-body}argument-list中参数的个数比原operator_symbol所需要的参数个数少一个(后置“++”、“--”除外)例如classComplex{public:Complex(double=0.0,double=0.0);//constructorComplexoperator+(constComplex&)const;//additionprivate:doublereal;//realpartdoubleimaginary;//imaginarypart};ComplexComplex::operator+(constComplex&operand2)const{returnComplex(real+operand2.real,imaginary+operand2.imaginary);}北京大学《程序设计实习》课程20运算符重载为成员函数实现单目运算单目运算:opoperand假如operand是类A的对象op应该重载为A的成员函数,该函数没有参数return_typeoperatorop()return_type是opoperand的类型例如:!string_s,等价于string_s.operator!()classString{public:String(constchar*=);//conversion/defaultconstructor~String();//destructorbooloperator!()const{returnlength