程序设计实习运算符重载.ppt

上传人:牧羊曲112 文档编号:6482013 上传时间:2023-11-04 格式:PPT 页数:62 大小:318.82KB
返回 下载 相关 举报
程序设计实习运算符重载.ppt_第1页
第1页 / 共62页
程序设计实习运算符重载.ppt_第2页
第2页 / 共62页
程序设计实习运算符重载.ppt_第3页
第3页 / 共62页
程序设计实习运算符重载.ppt_第4页
第4页 / 共62页
程序设计实习运算符重载.ppt_第5页
第5页 / 共62页
点击查看更多>>
资源描述

《程序设计实习运算符重载.ppt》由会员分享,可在线阅读,更多相关《程序设计实习运算符重载.ppt(62页珍藏版)》请在三一办公上搜索。

1、程序设计实习运算符重载,回顾:类和对象,类的定义、成员属性、成员函数、类的作用域对象的创建、存储、访问构造函数、析构函数定义、调用时机特殊的构造函数:复制构造函数、转换构造函数、初始化列表类的特殊成员:static成员、const成员、引用成员const对象成员对象和封闭类友元this指针,课堂问题,指出下列各题中的错误,并说明如何改正void Time(int);class Time private:int hour=12;int minute=0,second=0;int Time(int nHour,int nMin,int nSec);以下关于 this 指针的说法中不正确的是:A.c

2、onst成员函数内部不可以使用this 指针B.成员函数内的this 指针,指向成员函数所作用的对象。C.在构造函数内部可以使用this指针D.在析构函数内部可以使用 this 指针,构造函数和析构函数不能有返回类型;成员属性不能在类定义时初始化,const成员函数内部可以使用this 指针:是一个const指针,不能改变this的地址及所指向的值,课堂问题,指出下列题中的错误,并说明如何改正class X X(int i,int j):base(i),rem(base%j)int rem,base;如下定义和申明中哪些是错误的,如何改正:/example.hclass Examplepubl

3、ic:static double rate=6.5;static const int nSize=20;static Time Time(12,0,0);/example.c#include“example.h”double Example:rate;Time Example:Time;,Base应在rem之前定义;或rem的初始化时不使用base,直接用i,静态成员变量或成员对象不能在定义时初始化,应在.c程序中以全局变量的方式初始化;静态const类型则可以,课堂问题,以下程序编译、连接都能通过,请写出运行时输出的结果。你认为没有输出的,就写无输出#include using namesp

4、ace std;class Sample int A;static int B;public:Sample(int a)A=a,B+=a;static void func(Sample s);void Sample:func(Sample s)coutA=s.A,B=Bendl;int Sample:B=0;void main()Sample s1(2),s2(5);Sample:func(s1);Sample:func(s2);,静态成员函数的使用方法。其中的数据成员B是静态数据成员,求B之值是在构造函数中进行的。所以输出为:A=2,B=7 A=5,B=7,内容提要,抽象数据类型与运算符重载

5、两种运算符重载的实现方式常见的运算符重载流运算符:、自增运算符+、自减运算符-抽象数据类型的强制类型转换示例程序作业,抽象数据类型与运算符重载,C+预定义了一组运算符,用来表示对数据的运算+、-、*、/、%、&、!、|、=、!=、只能用于基本的数据类型:整型、实型、字符型、逻辑型、cin和cout使用运算符“”进行流操作时,要求操作数是基本数据类型,C+提供了数据抽象的手段,允许用户定义抽象数据类型:类通过调用类的成员函数,对它的对象进行操作但是,在有些时候,用类的成员函数来操作对象时,很不方便。例如对一个群体,按照他们的体重指数进行排序:涉及不同对象中的“体重指数”成员属性在数学上,两个复数

6、可以直接进行+、-等运算。但在C+中,直接将+或-用于复数是不允许的,抽象数据类型与运算符重载,运算符重载,我们希望:对一些抽象数据类型,也能够直接使用C+提供的运算符程序更简洁代码更容易理解例如bool compareQuata=Bill JimmyBill和Jimmy是CMan的两个对象比较他们的体重指数complex_a+complex_bcomplex_a和complex_b是两个复数对象求两个复数的和,对已有的运算符(C+中预定义的运算符)赋予多重的含义,使同一运算符作用于不同类型的数据时导致不同类型的行为目的是:扩展C+中提供的运算符的适用范围,以用于类所表示的抽象数据类型。同一个

7、运算符,对不同类型的操作数,所发生的行为不同(5,10i)+(4,8i)=(9,18i)5+4=9,运算符重载,class Complex public:Complex(double r=0.0,double i=0.0)real=r;imaginary=i;double real;/real partdouble imaginary;/imaginary part;,示例:复数类型定义,若能对+进行重新定义如下:Complex operator+(const Complex,示例:复数类型定义,对类Complex重载运算符号“+”,示例:复数的运算符重载,class Complex publ

8、ic:Complex(double=0.0,double=0.0);/constructorComplex operator+(const Complex,问题:为什么使成员函数、参数及返回值为常数类型?,/Overloaded addition operatorComplex Complex:operator+(const Complex/enables cascading/函数的返回值定义为const,因为返回的是this指针,Complex x,y(4.3,8.2),z(3.3,1.1);x=y+z;/y.operator+(z)/x.operator=(y.operator+(z)x=

9、y-z;/x.operator=(y.operator-(z),运算符重载,实质是函数重载:在程序编译时把指定的运算表达式转换成对运算符函数的调用把运算的操作数转换成运算符函数的参数根据实参的类型决定调用哪个运算符函数C+中运算符重载的例子:“”和“”是用于移位的运算符,通过C+的标准类库分别被重载为流输入和流输出运算符,运算符重载:注意,C+不允许定义新的运算符 通过重载现有的运算符,使它在用于类的对象时具有新类型的含义重载后运算符的含义应该符合日常习惯complex_a+complex_bword_a word_bdate_b=date_a+n有时使用函数调用更好older(student

10、_a,student_b)的语义比student_a student_b更清晰:年龄大小、身材高矮、体型胖瘦、重载不改变运算符的优先级、结合性、语法结构及参数个数以下运算符不能被重载:“.”、“.*”、“:”、“?:”、sizeof教材p.100列出了可重载的运算符,运算符重载的形式,重载为类的成员函数return_type operator operator_symbol(argument-list)function-body 重载为类的友员函数friend return_type operator perator_symbol(argument-list)function-body ope

11、rator_symbol必须是C+中可以重载的运算符符号,例如“+”、“-”、重载运算符“调用()、下标、成员访问-或者赋值运算符=”时,运算符重载函数必须声明为类的成员函数,运算符重载为成员函数,return_type operator operator_symbol(argument-list)function-body argument-list中参数的个数比原operator_symbol所需要的参数个数少一个(后置“+”、“-”除外)例如class Complex public:Complex(double=0.0,double=0.0);/constructorComplex op

12、erator+(const Complex,运算符重载为成员函数实现单目运算,单目运算:op operand假如operand是类A的对象op应该重载为A的成员函数,该函数没有参数return_type operator op()return_type是op operand的类型例如:!string_s,等价于string_s.operator!()class String public:String(const char*=);/conversion/default constructorString();/destructorbool operator!()const return len

13、gth=0;/is String empty?private:int length;/string length char*sPtr;/pointer to start of string;,运算符重载为成员函数实现双目运算,双目运算:operand_1 op operand_2 假设operand_1是类A的对象op应该重载为A的成员函数,该函数只有一个参数return_type operator op(argument_type argument)return_type是operand_1 op operand_2的类型argument_type是operand_2的类型被重载双目运算符的

14、两操作数类型可以相同class String public:String(const char*=);/conversion/default ctorString();/destructorbool operator=(const String,运算符重载为成员函数实现双目运算,被重载双目运算符的两操作数类型可以不同例如:set_a+element_a,等价于set_a.operator+(element_a)class CSet public:CStet();/constructorconst CSet,运算符重载为成员函数:小结,将运算符op重载为类A的成员函数时op是单目运算:在op所在

15、的表达式中,op右边的操作数是类A的对象return_type operator op()op operand等价于operand.operator op()op是双目运算:在op所在的表达式中,op左边的操作数是类A的对象return_type operator op(argument_type argument)operand_1 op operand_2等价于operand_1.operator op(operand_2)operand_2可以是A的对象,也可以不是,运算符重载为友员函数,但是,在一些情况下,对类A进行双目运算符op的重载时,类A的对象只能作为op所在表达式的右操作数,左

16、操作数不是A的对象将流操作符“”用于学生对象:coutstudent将“+”用于日期型对象:给定一个日期date,计算n天后的日期date+n:此时可以把“+”重载为成员函数date.operator+(n);n+date:怎么办?不允许这样写显然不符合思维的习惯,也失去了运算符重载的意义,运算符重载为友员函数,friend return_type operator operator_symbol(argument-list)function-body argument-list中参数的个数与原operator_symbol所需要的参数个数相同class String friend ostre

17、am,运算符重载为友员函数,实现单目运算:op operandoperand是类A的对象op应该重载为A的友员函数,该函数有一个参数friend return_type operator op(A arg)return_type是op operand的类型例如:!string_s,等价于operator!(string_s)class String friend bool operator!(const String,运算符重载为友员函数,实现双目运算:operand_1 op operand_2op被重载为A的友员函数,该函数有两个参数friend return_type operator

18、op(argT1 arg1,argT2 arg2)return_type是operand_1 op operand_2的类型argT1是operand_1的类型argT2是operand_2的类型operand_1和operand_2中至少有一个是类型为A的对象如果operand_1是类A的对象,则argT1为A在函数operator op(argT1 arg1,argT2 arg2)的函数体中,可以访问类arg1的任何数据成员如果operand_2是类A的对象,则argT2为A 在函数operator op(argT1 arg1,argT2 arg2)的函数体中,可以访问类arg2的任何数据

19、成员将双目运算符op重载为类A的友员函数时,可以:以非类A的对象作为op所在表达式的左操作数,流输入输出运算符的重载,cout 5“this”;为什么能够成立?cout是什么?“”为什么能用在 cout上?,cout 是在 iostream中定义的,ostream 类的对象“”能用在cout 上是因为 在iostream.h里对“”进行了重载考虑,怎么重载才能使得cout 5;和 cout“this”都能成立?,流输入输出运算符的重载,void operator(const ostream,流输入输出运算符的重载,怎么重载才能使得cout 5“this”;能成立?,流输入输出运算符的重载,只需

20、要将重载运算符的返回值设为引用ostream,流输入输出运算符的重载,引用,某个变量的引用,和这个变量是一回事,相当于该变量的一个别名。void swap(int/n1,n2的值被交换,引用,函数的返回值可以是引用,如:#include using namespace std;int n=4;int 该程序输出结果是 40,const 引用类型参数,class Complex;Complex Add(Complex c1,Complex c2);Complex Add(const Complex const 代表参数的值在函数内部不能被修改两种函数定义方式,后者比前者好在哪里呢?后者的好处是避

21、免了生成参数对象的过程,节省时间,空间开销。,对象指针和对象引用作函数的参数,对象作为函数的参数值传递,但需进行对象副本的拷贝对象指针作函数的参数使用对象指针作为函数参数要比使用对象作函数参数更普遍一些,有如下两点好处:(1)实现传址调用。可在被调用函数中改变调用函数的参数对象的值,实现函数之间的信息传递。(2)使用对象指针实参仅将对象的地址值传给形参,而不进行副本的拷贝,这样可以提高运行效率,减少时空开销。当形参是指向对象指针时,调用函数的对应实参应该是某个对象的地址值,一般使用&后加对象名。,#include using namespace std;class Mpublic:M()x=y

22、=0;M(int i,int j)x=i;y=j;void copy(M*m);void setxy(int i,int j)x=i;y=j;void print()coutx;y=m-y;void fun(M m1,M*m2);int main()M p(5,7),q;q.copy(,输出结果为:5,7 22,25,对象指针和对象引用作函数的参数,对象引用作函数参数 在实际中,使用对象引用作函数参数要比使用对象指针作函数更普遍使用对象引用作函数参数具有用对象指针作函数参数的优点用对象引用作函数参数将更简单,更直接。,#include using namespace std;class M p

23、ublic:M()x=y=0;M(int i,int j)x=i;y=j;void copy(M,假定下面程序输出为 5,请问该补写些什么?#include using namespace std;class CStudentpublic:int nAge;int main()CStudent s;s.nAge=5;cout s;return 0;,流输入输出运算符的重载,ostream,流输入输出运算符的重载,问题:cout 5“this”;本质上的函数调用的形式是什么?(用重载后的写出),operator(operaotr(cout,5),“this”);,思考,int n=5;cout

24、n+n;输出结果是什么?结果是为什么?,思考,因为cout n+n;可以理解成:operator(operator(cout,n+),n);而C/C+参数的计算顺序是从右到左,所以先入栈不是仅对cout成立即先将最右边的n入栈,在将n+入栈。之后先将n+出栈,输出n并执行自增运算,再出栈并输出n的栈中所存值,流输入输出运算符的重载,事实上在 iostream 里是将重载成成员函数class ostream ostream的函数调用形式是什么呢?,流输入输出运算符的重载,是:cout.operator(n+).operator(n);实际上,这条语句可以直接写在程序里,其效果和cout n+n;

25、完全一样为什么?,class PhoneNumber friend ostream,示例:用友元函数重载输入输出流,istream,输入流的函数::ignore(n)/忽略n个输入字符:setw(n)/限定读到每个字符数组的字符个数,产生调用operator(cin,phone);,返回值为引用,使得在Phonenumber上的对象输入操作可以串联:cin phone1 phone2;,注意:函数 operator被声明为PhoneNumber的友员函数,因为按照日常习惯,PhoneNumber的对象只能作为的右操作数总结:流运算符重载对于任何类A,如果希望对它重载流运算符“”,应该将函数 o

26、perator声明为A的友员函数重载流运算符“”时,函数 operator的第一个操作数类型和返回值类型都必须是istream&,示例:用友元函数重载输入输出流,数组下标运算符重载,对数组对象,经常希望能够对其中的某个元素进行取值、赋值C=array5array6=8在重载“”时,使用eleType,int 如果在Array定义中用“int operator(int)”代替“int&operator(int)”,则“integers15=1000”是错误的,#include void assert(int expression);assert的作用是现计算表达式expression,如果其值为

27、假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。,重载成员访问操作符:“*”、“-”,class Screen;class ScreenPtr public:Screen const版本和非const版本区别:const成员返回const引用以防止用户改变基础对象,重载成员访问操作符,成员访问操作符与下标操作符一样,一般应该定义const版本和非const版本。解引用操作符(*)不要求定义为成员函数。箭头操作符(-)必须定义为类成员函数,必须返回指向类类型的指针,或者返回定义了自己的箭头操作符的类类型对象。像一个二元操作符:接受一个对象和一个成员

28、名,但事实上它不接受显式形参。例如:Ptr*operator-()return ptr;。这里没有形参,由编译器处理获取成员的工作。编写程序:ptr-action()时,实际上等价于:(ptr-action)()。而编译器按如下规则对ptr-action求值:ptr是一个指针,指向具有名为action的成员的类对象,则编译器将代码编译为调用该对象的action成员。否则,如果action是定义了operator-操作符的类的一个对象,则ptr-action与ptr.operator-()-action相同。即,执行ptr的operator-(),然后使用该结果重复这三步。否则代码出错,重载+和

29、-运算符,自增运算符+、自减运算符-有前置/后置之分,为了区分所重载的是前置运算符还是后置运算符,C+规定前置运算符作为一元运算符重载class_a&operator+()或friend class_a&operator+(class_a&)class_a&operator-()或friend class_a&operator-(class_a&)后置运算符作为二元运算符重载class_a operator+(int)或friend class_a operator+(class_a&,int)class_a operator-(int)或friend class_a operator-(cl

30、ass_a&,int)obj+:obj.operator+(0)、或者operator+(obj,0)+obj:obj.operator+()、或者operator+(obj),实参0为“哑值”,用于使编译器区分前置还是后置,问题:为什么前置返回值为对象引用,而后置返回值为对象?,class Date public:Date(int m=1,int d=1,int y=1900);/constructorDate,Date not a reference return/后置形式叫做“取回然后增加”。void Date:dateIncrement(),Date d4(3,18,1969);+d4

31、;/call d4.operator+()d4+;/call d4.operator+(0),如何选择使用哪种方式重载?,对于单目运算符(后置“+”、“-”除外),通常只需要重载为成员函数对于双目运算符,如果表达式的左右操作数都相同,也只要重载为成员函数对于双目运算符op,在许多情况下都希望:对类A进行重载后,表达式的左操作数可以是A的对象,也可以不是A的对象例如对于字符串类String,重载“+”,合并两个字符串s1+s2:s+“abc”:“abc”+s同时将函数operator op重载为A的成员函数和友员函数支持左操作数为类A的对象String operator+(const Strin

32、g&)String operator+(const char*)支持左操作数为非类A的对象friend String operator+(const char*,const String&),this指针,this是C+中用来表示当前对象地址的一个隐含指针变量。当对一个对象调用成员函数时,编译程序先将对象的地址赋给this指针,然后调用成员函数,每次成员函数存取数据成员时,由隐含作用this指针。可以使用*this来标识调用该成员函数的对象。在类的成员函数中需要当前对象的引用时,用“*this”表示。例如:在重载前置自增运算时,需要返回当前对象的引用引用:对象的别名,直接指向目标,不分配空间,

33、不需要销毁赋值必须返回*this当前对象的地址时,用“this”表示。例如:需要把当前对象的地址传递给某个函数调用,抽象数据类型的强制类型转换,在一些基本数据类型之间,C+允许进行强制类型转换float_b=(float)int_a:把int_a强制转换成float型数据int_a=(int)char_c:把char_c强制转换成int型数据对类A表示的抽象数据类型,如何将它的对象转换成其他类型的数据?使用非静态成员函数对A进行运算符重载,这种运算符称作“转换运算符”operator int()const“(int)A_obj”等价于“A_obj.operator int()”,返回值类型是i

34、ntoperator otherClass()const“(otherClass)A_obj”等价于“A_obj.operator otherClass()”,返回值类型是otherClass对于转换运算符,不能够为重载成员函数指定返回值类型,转换运算符本身就代表了返回值类型,转换运算符,转换操作符(conversion operator)是一种特殊的类成员函数,其形式为:operator type();其中,type表示内置类型名、类类型名或由类型别名所定义的名字。对任何可作为函数返回类型的类型(void除外)都可以定义转换函数。一般而言,不允许转换为数组或函数类型,转换为指针类型(数据和函数指针)以及引用类型是可以的。转换函数并且形参表必须为空。通常转换操作符应定义为const成员。,示例程序,CMan类运算符重栽man5:man的身高增长了5厘米man+8:man的体重增长了8公斤7+man:man的体重增长了7公斤强制类型转换quota=(float)man:把man根据他的体重指数转换成一个浮点数程序放到网上,课后阅读,作业,阅读教材邮件作业大整数运算练习:请编写一个用于超长整数处理的类,使得下列程序能正确运行。假设每个超长整数最多有100位十进制整数。,

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

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号