《运算符重载与友元.ppt》由会员分享,可在线阅读,更多相关《运算符重载与友元.ppt(56页珍藏版)》请在三一办公上搜索。
1、第6章 运算符重载与友元,面向对象程序设计,2023/10/19,第6章运算符重载与友元,2,内容提要,运算符重载的目的、定义和实质 运算符重载的规则 运算符重载的两种形式 友元的作用和定义,2023/10/19,第6章运算符重载与友元,3,提出问题,复数的加减运算问题:对于非基本数据类型,如复数、分数,如何在程序中进行运算?能否直接用运算符(+、-、*、/)进行运算?,2023/10/19,第6章运算符重载与友元,4,分析问题,自定义一个复数类Complex完成复数的加减运算设计复数类class Complex/复数类public:Complex(double r=0.0,double i=
2、0.0)/构造函数 real=r;image=i;private:double real,image;/定义实部、虚部;,2023/10/19,第6章运算符重载与友元,5,思考,是否能通过下面的代码完成复数的加减运算:int main()/定义一个复数对象c1,其实部为2,虚部为2.5 Complex c1(2,2.5);Complex c2(3,1.4);Complex c3,c4;c3=c1+c2;c4=c1-c2;return 0;,2023/10/19,第6章运算符重载与友元,6,编译程序,显示:,2023/10/19,第6章运算符重载与友元,7,说明,C+预定义的“+”、“-”运算只
3、支持基本数据类型,并不支持用户自定义类型。复数类的加减运算不能采用系统预定义的运算符“+”、“-”完成,那么编写成员函数来实现加、减运算。,2023/10/19,第6章运算符重载与友元,8,重新设计复数类Complex,class Complex public:Complex(double r=0.0,double i=0.0)/构造函数 real=r;image=i;double Real()return real;/返回复数的实部 double Imag()return image;/返回复数的虚部 Complex add(Complex,2023/10/19,第6章运算符重载与友元,9,
4、完成复数与复数相加Complex Complex:add(Complex,成员函数定义,2023/10/19,第6章运算符重载与友元,10,完成复数与实数相加Complex Complex:add(double d)Complex temp;temp.real=real+d;temp.image=image;return temp;完成复数与复数相减Complex Complex:sub(Complex,2023/10/19,第6章运算符重载与友元,11,完成复数与实数相减Complex Complex:sub(double d)Complex temp;temp.real=real-d;te
5、mp.image=image;return temp;完成复数间的赋值运算void Complex:set_value(Complex,2023/10/19,第6章运算符重载与友元,12,int main()Complex c1(2,2.5);Complex c2(3,1.4);Complex c3,c4;c3.set_value(c1.add(c2);c4.set_value(c1.sub(c2);coutc3=c3.Real()+i c3.Imag()endl;coutc4=c4.Real()+i c4.Imag()endl;return 0;,不如c3=c1+c2直观!,2023/10/
6、19,第6章运算符重载与友元,13,用函数的方式将复数的加减运算表示出来远不如用运算符“+”、“-”直观 如果复数的运算能够用已有的运算符表示出来,则程序的易读性会大大增强,同时更符合人的思维习惯 C+提供了运算符重载机制,使得系统预定义的运算符能够完成用户自定义数据类型的运算,说明,2023/10/19,第6章运算符重载与友元,14,运算符重载的定义,赋予系统预定义的运算符多重含义,使同一个运算符既可以作用于预定义的数据类型,也可以作用于用户自定义的数据类型 重载运算符为类的成员函数,其具体语法格式为::operator();,2023/10/19,第6章运算符重载与友元,15,在复数类中重
7、载运算符,class Complex/复数类public:Complex(double r=0.0,double i=0.0)real=r;image=i;const double Real()return real;const double Imag()return image;Complex operator+(Complex,2023/10/19,第6章运算符重载与友元,16,operator是进行运算符重载的关键字是该运算符涉及的操作数运算符重载为成员函数最多有一个形参 运算符重载的实质就是函数重载,只不过函数名换成了关键字operator和具体要重载的运算符了但是运算符重载也有别于函
8、数重载,运算符重载的函数参数就是该运算符涉及的操作数,因此运算符重载在参数个数上是有限制的,这是它不同于函数重载之处。,说明,2023/10/19,第6章运算符重载与友元,17,例6-2,#include using namespace std;class MyStringpublic:MyString(const char*=0);/定义构造函数 MyString(const MyString,2023/10/19,第6章运算符重载与友元,18,MyString:MyString(const MyString,赋值构造函数,2023/10/19,第6章运算符重载与友元,19,重载operat
9、or=,MyString,2023/10/19,第6章运算符重载与友元,20,重载operator=,MyString,2023/10/19,第6章运算符重载与友元,21,重载operator,/返回第i个位置的字符char,2023/10/19,第6章运算符重载与友元,22,重载operator=,bool MyString:operator=(const MyString,2023/10/19,第6章运算符重载与友元,23,int main()MyString s(How are you?),s1=s;cout字符串How are you?第6个位置的字符是:s5endl;if(s=How
10、)cout两字符串比较结果:equalendl;elsecout两字符串比较结果:unequalendl;s1=Fine;return 0;,if(How=s)是否可以?,2023/10/19,第6章运算符重载与友元,24,说明,在重载赋值运算符时,要注意进行自赋值检测。所谓自赋值是指将对象赋值给它本身。运算符重载使系统预定义的运算符可以作用于用户自定义类型,但绝不能改变运算符原有的优先级、结合性以及语法结构。运算符重载为成员函数时,左操作数必须是对象本身,2023/10/19,第6章运算符重载与友元,25,运算符重载的规则,重载的功能应当与原有功能类似,不能改变原运算符的操作数个数,同时至少
11、要有一个操作数的类型是自定义类型。重载之后运算符的优先级和结合性都不会改变,并且要保持原运算符的语法结构。参数和函数值类型都可以重新说明。,2023/10/19,第6章运算符重载与友元,26,不能重载的运算符,2023/10/19,第6章运算符重载与友元,27,思考,能否在例6-3中实现if(How=s)?是否可以将operator=实现为如下形式?bool operator=(const char*pstr,const MyString 其中,第一个参数pstr代表运算符=的左操作数,第二个参数str1代表右操作数,2023/10/19,第6章运算符重载与友元,28,根据类的封装性,一般将数
12、据成员声明为私有成员,外部不能直接访问,只能通过类的公有成员函数对私有成员进行访问。有时,需要频繁地调用成员函数来访问私有成员,这就存在一定的系统开销。C+从高效的角度出发,提供友元机制,使被声明为友元的全局函数或者其他类可以直接访问当前类中的私有成员,又不改变其私有成员的访问权限。,友元,2023/10/19,第6章运算符重载与友元,29,友元可以是一个全局函数,也可以是一个类的成员函数,还可以是一个类。如果友元是函数,则称为友元函数。如果友元是一个类,则称为友元类。友元类的所有成员函数都是友元函数,可以访问被访问类的任何成员。友元声明以关键字friend开始,只能出现在被访问类的定义中。具
13、体格式如下 friend();friend class;,友元的定义,2023/10/19,第6章运算符重载与友元,30,例6-3,class MyString;bool operator=(const MyString,2023/10/19,第6章运算符重载与友元,31,bool operator=(const MyString,2023/10/19,第6章运算符重载与友元,32,int main()MyString s(How are you?);if(How=s)cout两字符串比较结果:equalendl;elsecout两字符串比较结果:unequalendl;return 0;,2
14、023/10/19,第6章运算符重载与友元,33,说明,友元函数operator=是一个全局函数,但作为MyString类的友元,它只能在MyString类中声明。而友元函数的实现既可以在MyString类外实现也可以在类中实现。无论在哪里实现,友元函数都须通过对象名访问类中的私有成员。在例6-4中,对MyString类和友元函数operator=进行了前向声明,从语法上讲,这个前向声明应该是不必要的。但是在VC6.0的标准名字空间中,这个前向声明是必须的。这是VC6.0本身的缺陷所导致,可以通过下载相关补丁程序弥补该缺陷,在VC+的后续版本中不存在这个缺陷。,2023/10/19,第6章运算
15、符重载与友元,34,例6-4 友元类,#include#include using namespace std;class date;/类的前向声明class studentpublic:student(char*pid,char*pname,char*pdept)id=pid;name=pname;dept=pdept;void display(date,2023/10/19,第6章运算符重载与友元,35,class date friend class student;/友元类声明public:date(int y=2000,int m=1,int d=1):year(y),month(m)
16、,day(d)private:int year;int month;int day;,2023/10/19,第6章运算符重载与友元,36,void student:display(date,2023/10/19,第6章运算符重载与友元,37,友元的出现主要是为了解决一些实际问题,友元本身不是面向对象的内容。通过友元机制,一个类或函数可以直接访问另一类中的非公有成员。可以将全局函数、类、类的成员函数声明为友元。友元关系是不能传递的。B类是A类的友元,C类是B类的友元,C类和A类之间,如果没有声明,就没有任何友元关系,不能进行数据共享。友元关系是单向的,如果声明B类是A类的友元,B类的成员函数就可
17、以访问A类的私有成员和保护成员。但A类的成员不能访问B类的私有成员和保护成员,除非声明A类是B类的友元。友元关系是不能继承的。B类是A类的友元,C类是B类的派生类,则C类和A类之间没有任何友元关系,除非C类声明A类是友元。,友元知识小结,2023/10/19,第6章运算符重载与友元,38,运算符重载为类的友元函数,语法形式friend operator();运算符重载为类的友元函数最多只能有两个参数如果重载双目运算符,则第一个参数代表左操作数,第二个参数代表右操作数,2023/10/19,第6章运算符重载与友元,39,例6-9,class Triangle public:Triangle(in
18、t i,int j,int k)double s;x=i;y=j;z=k;s=(x+y+z)/2.0;area=sqrt(s*(s-x)*(s-y)*(s-z);void disparea()coutArea=areaendl;/运算符重载为友元函数friend const double operator+(Triangle,2023/10/19,第6章运算符重载与友元,40,int main()Triangle t1(3,4,5),t2(4,5,6);double s;coutt1:;t1.disparea();coutt2:;t2.disparea();s=t1+t2;cout总面积=se
19、ndl;return 0;,2023/10/19,第6章运算符重载与友元,41,运算符重载的基本方针,2023/10/19,第6章运算符重载与友元,42,“+”重载为成员函数形式,#include using namespace std;class Clock/时钟类 public:Clock(int NewH=0,int NewM=0,int NewS=0);void ShowTime();void operator+();/前缀运算符重载函数的声明/后缀运算符重载函数,加int参数以示区分 void operator+(int);private:int Hour,Minute,Second
20、;,2023/10/19,第6章运算符重载与友元,43,void Clock:operator+()/前缀单目运算符重载函数的实现 Second+;if(Second=60)Second=Second-60;Minute+;if(Minute=60)Minute=Minute-60;Hour+;Hour=Hour%24;cout+Clock:;,2023/10/19,第6章运算符重载与友元,44,void Clock:operator+(int)/后缀单目运算符重载函数的实现 Second+;if(Second=60)Second=Second-60;Minute+;if(Minute=60)
21、Minute=Minute-60;Hour+;Hour=Hour%24;coutClock+:;,2023/10/19,第6章运算符重载与友元,45,说明,运算符重载为类的成员函数时,函数的参数个数比原来操作数少一个(后缀“+”和后缀“-”除外)。运算符重载为成员函数后,它可以自由地访问类的所有成员。实际使用时,总是通过该类的某个对象来访问重载的运算符。如果是双目运算符,左操作数一定是对象本身,由this指针给出,另一个操作数需要由运算符重载的参数表来传递。如果是单目运算符,操作数由对象的this指针给出,就不再需要任何参数。但重载“+”和“-”运算符时,C+约定,如果在参数表中放一个整形参数
22、,则表示重载的运算符为后缀运算符。,2023/10/19,第6章运算符重载与友元,46,解决问题,class Complex/复数类public:Complex(double r=0.0,double i=0.0)real=r;image=i;const double Real()return real;const double Imag()return image;/重载运算符+,复数加复数 friend const Complex operator+(const Complex,2023/10/19,第6章运算符重载与友元,47,const Complex operator+(const
23、Complex,2023/10/19,第6章运算符重载与友元,48,const Complex operator-(const Complex/*this表示当前对象,2023/10/19,第6章运算符重载与友元,49,int main()Complex c1(3,4),c2(5,6),c3,c4;/定义复数类的对象 coutc1=c1.Real()+ic1.Imag()endl;coutc2=c2.Real()+ic2.Imag()endl;c3=c1+c2;/重载运算符+、=,完成复数加复数 coutc3=c1+c2=c3.Real()+ic3.Imag()endl;c3=c3+6.5;/
24、重载运算符+、=,完成复数加实数 coutc3+6.5=c3.Real()+ic3.Imag()endl;c4=c2-c1;/重载运算符-、=,完成复数减复数 coutc4=c2-c1=c4.Real()+ic4.Imag()endl;return 0;,2023/10/19,第6章运算符重载与友元,50,在C+标准库中,已经为用户提供了与复数有关的库函数,它们包含在头文件中。在实际应用中,用户只需要将此头文件包含到源程序文件中即可。对于任何形参,如果仅需要从函数中读而不改变它,默认地应该作为const引用来传递它。所有赋值运算均改变左值(左值是可以被赋值的表达式,位于赋值语句的左侧),因此,
25、所以赋值运算的返回值对于左值应该是非常量引用。,说明,2023/10/19,第6章运算符重载与友元,51,举一反三,#include using namespace std;class RMB/定义人民币类RMBpublic:RMB(double value=0.0)/构造函数 yuan=(int)value;jiao=(int)(value-yuan)*10);fen=(int)(value*100-yuan*100-jiao*10);void print()coutyuan元jiao角fen分endl;operator double()/重载类型转换运算符double,没有函数值类型 re
26、turn yuan+jiao*0.1+fen*0.01;private:int yuan,jiao,fen;,2023/10/19,第6章运算符重载与友元,52,int main()RMB a(3.45),b(2.11);/定义2个RMB类的对象a、b/将两个对象a、b强制转换为实数,再相加,结果用于初始化对象c RMB c=RMB(double)a+(double)b);a.print();b.print();c.print();return 0;,2023/10/19,第6章运算符重载与友元,53,本章小结,运算符重载是赋予系统预定义的运算符多重含义,使得预定义运算符能够对类对象进行运算。
27、运算符重载实质上就是函数重载,但不同的是,运算符重载函数对参数个数有限制,并保持优先级、结合性以及语法结构不变等特性。,2023/10/19,第6章运算符重载与友元,54,本章小结,运算符重载不是每个程序必须具有的功能,它的出现只是为了增加程序的易读性。运算符重载不是新的机制,其实质是函数重载。与函数重载不同的是,运算符重载在参数上有限制。运算符重载有两种形式:重载为类的成员函数、重载为类的友元函数。当运算符重载为成员函数时,左操作数一定是当前对象本身,而重载为友元函数时,该运算符所涉及的所有操作数都必须出现在函数的参数列表当中。操作数出现的顺序按照参数从左到右出现的顺序决定。,2023/10/19,第6章运算符重载与友元,55,类的友元可以访问类的所有成员。友元可以是普通函数,其他类的成员函数,也可以是其他类。友元关系既不能传递、也不能继承、也不可逆。友元不是纯面向对象的产物,它在类之间、类与普通函数之间共享了内部封装的数据,破坏了类的封装性,设计它的目的是为了实用。因此,在实际编程过程中,应尽量避免使用友元。,2023/10/19,第6章运算符重载与友元,56,常见错误,臆造新的符号作运算符 运算符重载为成员函数和友元函数时参数个数问题 前缀与后缀运算符重载的区分问题,
链接地址:https://www.31ppt.com/p-6350464.html