《第6章运算符重载.ppt》由会员分享,可在线阅读,更多相关《第6章运算符重载.ppt(50页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第六章 运算符重载引言运算符和函数4=1+3 4.0=1.0+3.0 函数名函数名参数参数int返回值返回值int函数名函数名参数参数double返回值返回值doubleint +(int,int);double +(double,double);可以将可以将+代表的操作看成一个函数:代表的操作看成一个函数:+为函数的名字,为函数的名字,+操作操作的两个操作数的类型即为函数形参的类型,的两个操作数的类型即为函数形参的类型,+操作的结果的操作的结果的类型即为函数的返回值类型。类型即为函数的返回值类型。引言运算符重载的提出C/C+C/C+中,每种基本数据类型的变量都可通过几种运算符来做相关计算,中
2、,每种基本数据类型的变量都可通过几种运算符来做相关计算,如如intint型变量,它们可以同型变量,它们可以同“+”,“-”,“*”,“/”等运算符来做等运算符来做加法,减法,乘法,除法等。如:加法,减法,乘法,除法等。如:int a,b;a+b;a-b;a*b;a/b;class Vectorint*data;int num;public:我们能否将自定义的类的对象也通过我们能否将自定义的类的对象也通过“+”,“-”,“*”,“/”等运算符来进行两个对象的加,减,乘,除呢?如:等运算符来进行两个对象的加,减,乘,除呢?如:Vector vec1,vec2;vec1+vec2;vec1-vec2
3、;vec1*vec2;vec1/vec2;定义一个向量类定义一个向量类两个向量类对象的加减乘除两个向量类对象的加减乘除C+C+提供了运算符重载机制来帮助我们实现上述目的。提供了运算符重载机制来帮助我们实现上述目的。主要内容6.1 基本语法6.2 常用运算符的重载6.3 赋值运算符的重载6.4 输入输出运算符的重载6.5 运算符的重载6.6 用户自定义类型转换6.1 基本语法在C+中,为一个类类型定义运算符函数和定义普通函数的形式很相似,只是函数的名字是关键字operator后紧跟要重载的运算符。例如,重载的”+”运算符函数名字为operator+。定义了运算符函数之后,就可以对类类型的操作数使
4、用该运算符。运算符函数声明的语法规则如下:friend 类型名类型名 operator运算符运算符(形参列表形参列表);friend friend 关键字可选,关键字可选,有有friendfriend关键字时表示运算符函数是类的友元函关键字时表示运算符函数是类的友元函数数,没有没有friendfriend关键字时表示运输符函数是类的成员函数或普通函数关键字时表示运输符函数是类的成员函数或普通函数。6.1 基本语法运算符函数声明的语法规则如下:friend 类型名类型名 operator运算符运算符(形参列表形参列表);形式列表中参数的个数取决于两个因素:形式列表中参数的个数取决于两个因素:1.
5、1.运算符是一元运算符还是二元运算符运算符是一元运算符还是二元运算符2.2.运算符函数是成员函数还是友元函数运算符函数是成员函数还是友元函数6.1 基本语法C+中内被重载的运算符有:C+中不能被重载的运算符有:6.1 基本语法注意事项虽然运算符重载提供了语法上的方便,但也有一虽然运算符重载提供了语法上的方便,但也有一些使用限制。些使用限制。只有只有C+预定义运算符预定义运算符集合中的运算符才集合中的运算符才可以重载可以重载 C+中有些运算符不能被重载:中有些运算符不能被重载::(作用域解析符)、(作用域解析符)、.(成员选择符)、(成员选择符)、.*(成员指针间接引用符)及(成员指针间接引用符
6、)及?:(条(条件运算符)。件运算符)。不能定义不能定义C+中没有的运算符中没有的运算符,如,如operator*会产生编会产生编译错误。译错误。6.1 基本语法注意事项内置类型的运算符的预定义意义不能改变内置类型的运算符的预定义意义不能改变,也不能也不能为内置数据类型定义其他运算符为内置数据类型定义其他运算符。例如,不能定义。例如,不能定义内置数组的内置数组的operator+。重载运算符不能改变运算符的优先级和结合性重载运算符不能改变运算符的优先级和结合性。重载运算符不能改变操作数的个数重载运算符不能改变操作数的个数。运算符重载不能滥用运算符重载不能滥用,只有当用户自定义类型上的操作只有当
7、用户自定义类型上的操作与内置运算符之间存在逻辑对应关系时,重载的运算与内置运算符之间存在逻辑对应关系时,重载的运算符才能使程序显得更自然、更直观。符才能使程序显得更自然、更直观。6.2 常用运算符的重载一元运算符的重载本节给出一些常规运算符本节给出一些常规运算符以成员函数和友元函数两种方以成员函数和友元函数两种方式重载式重载的例子。在下面的代码中,我们分别以两个类的例子。在下面的代码中,我们分别以两个类ByteByte和和IntegerInteger来举例说明如何使用成员函数和友元函来举例说明如何使用成员函数和友元函数重载常用的运算符。数重载常用的运算符。class Byte unsigned
8、 char b;public:Byte(unsigned char bb=0):b(bb);class Integer long i;public:Integer(long ll=0):i(ll);6.2 常用运算符的重载一元运算符的重载(成员函数形式)class Byte unsigned char b;public:Byte(unsigned char bb=0):b(bb)/无副作用的运算符定义为无副作用的运算符定义为 const成员函数成员函数 const Byte&operator+()const/正号正号 return*this;const Byte operator-()cons
9、t/负号负号 return Byte(-b);const Byte operator()const/按位取反按位取反 return Byte(b);Byte operator!()const/逻辑非逻辑非 return Byte(!b);Byte*operator&()/取地址取地址 return this;一元运算符函数是一元运算符函数是成员函数时,成员函数时,形式形式参数列表里没有参参数列表里没有参数数。6.2 常用运算符的重载一元运算符重载(成员函数形式)/有副作用的运算符定义为非有副作用的运算符定义为非const成员函数成员函数 const Byte&operator+()/前缀前缀+
10、b+;return*this;const Byte operator+(int)/后缀后缀+Byte before(b);b+;return before;const Byte&operator-()/前缀前缀-b;return*this;const Byte operator-(int)/后缀后缀-Byte before(b);-b;return before;自增和自减运自增和自减运算符有前缀和算符有前缀和后缀两种形式,后缀两种形式,都会改变对象,都会改变对象,所以不能对常所以不能对常量对象操作。量对象操作。前缀形式返回改变后前缀形式返回改变后的对象,返回的对象,返回*thisthis。后
11、缀形式返回改变之前后缀形式返回改变之前的值,所以必须创建一的值,所以必须创建一个代表这个值的独立对个代表这个值的独立对象并返回它象并返回它,是通过传是通过传值方式返回的。值方式返回的。6.2 常用运算符的重载一元运算符重载(成员函数形式)/重载运算符的使用示例重载运算符的使用示例int main()Byte b;+b;/b.operator+();-b;/b.operator-();b;/b.operator();Byte*bp=&b;/Byte*bp=b.operator&();!b;/b.operator!();+b;/b.operator+();b+;/b.operator+(int);
12、-b;/b.operator-();b-;/b.operator-(int);/end of main()运算符函数的调用运算符函数的调用有两种形式隐式调有两种形式隐式调用和显式调用。用和显式调用。显式调用显式调用隐式调用隐式调用程序在执行时实际调用程序在执行时实际调用Byte:operator(&b);为左侧为左侧main函数中的一函数中的一元运算符。元运算符。一元运算符重载(friend函数形式)/全局函数重载一元运算符,要带一个参数作为操作数全局函数重载一元运算符,要带一个参数作为操作数/全局运算符函数一般要声明为类的友元全局运算符函数一般要声明为类的友元class Integer lo
13、ng i;public:Integer(long ll=0):i(ll)/无副作用的运算符参数为无副作用的运算符参数为 const&friend const Integer&operator+(const Integer&a);friend const Integer operator-(const Integer&a);friend const Integer operator(const Integer&a);friend Integer*operator&(Integer&a);friend int operator!(const Integer&a);/有副作用的运算符参数为非有副作用
14、的运算符参数为非const引用引用 friend const Integer&operator+(Integer&a);/前缀前缀+friend const Integer operator+(Integer&a,int);/后缀后缀+friend const Integer&operator-(Integer&a);/前缀前缀+friend const Integer operator-(Integer&a,int);/后缀后缀+;/end of class Integer一元运算符函数一元运算符函数是友员函数或普是友员函数或普通函数时,通函数时,形式形式参数列表里有一参数列表里有一个参数个
15、参数。一元运算符重载(friend函数形式/全局运算符函数的定义全局运算符函数的定义const Integer&operator+(const Integer&a)return a;const Integer operator-(const Integer&a)return Integer(-a.i);const Integer operator(const Integer&a)return Integer(a.i);Integer*operator&(Integer&a)return a.This();/不能用不能用&a,会导致递归调用本函数,会导致递归调用本函数int operator!(
16、const Integer&a)return!a.i;一元运算符重载(friend函数形式/前缀,返回增加后的对象前缀,返回增加后的对象const Integer&operator+(Integer&a)a.i+;return a;/后缀,返回增加以前的对象值后缀,返回增加以前的对象值const Integer operator+(Integer&a,int)Integer before(a.i);a.i+;return before;const Integer&operator-(Integer&a)a.i-;return a;const Integer operator-(Integer&
17、a,int)Integer before(a.i);a.i-;return before;自增和自减运自增和自减运算符有前缀和算符有前缀和后缀两种形式,后缀两种形式,都会改变对象,都会改变对象,所以不能对常所以不能对常量对象操作。量对象操作。前缀形式返回改变后前缀形式返回改变后的对象,返回的对象,返回*thisthis。后缀形式返回改变之后缀形式返回改变之前的值,所以必须创前的值,所以必须创建一个代表这个值的建一个代表这个值的独立对象并返回它独立对象并返回它,是是通过传值方式返回的。通过传值方式返回的。一元运算符重载(friend函数形式/重载运算符的使用重载运算符的使用int main()I
18、nteger a;+a;-a;a;Integer*ip=&a;!a;+a;a+;-a;a-;/end of main程序在执行时调用程序在执行时调用operator(a);为左侧为左侧main函数中的函数中的一元运算符。一元运算符。6.2 常用运算符重载二元运算符重载(成员函数方式)class Byte unsigned char b;public:Byte(unsigned char bb=0):b(bb)const Byte operator+(const Byte&right)const return Byte(b+right.b);const Byte operator-(const
19、Byte&right)const return Byte(b-right.b);const Byte operator*(const Byte&right)const return Byte(b*right.b);const Byte operator/(const Byte&right)const assert(right.b!=0);return Byte(b/right.b);const Byte operator%(const Byte&right)const assert(right.b!=0);return Byte(b%right.b);二元运算符函数是成二元运算符函数是成员函数
20、时,员函数时,形式参数形式参数列表里只有一个参数,列表里只有一个参数,此参数为运算符的右此参数为运算符的右操作数操作数。二元运算符二元运算符的左操作数是调用操的左操作数是调用操作符函数的对象作符函数的对象。隐含参数隐含参数this指针指针+,-,*,/,%运算运算不改变操作数的值。不改变操作数的值。它们的计算结果产生它们的计算结果产生一个新的值,为此将一个新的值,为此将这几个函数的返回值这几个函数的返回值设置为设置为ByteByte。6.2 常用运算符重载二元运算符重载(成员函数方式)const Byte operator(const Byte&right)const return Byte(
21、b right.b);const Byte operator&(const Byte&right)const return Byte(b&right.b);const Byte operator|(const Byte&right)const return Byte(b|right.b);const Byte operator(const Byte&right)const return Byte(b(const Byte&right)const return Byte(b right.b);二元运算符函数是成二元运算符函数是成员函数时,员函数时,形式参数形式参数列表里只有一个参数,列表里只有一
22、个参数,此参数为运算符的右此参数为运算符的右操作数操作数。二元运算符二元运算符的左操作数是调用运的左操作数是调用运算符函数的对象,也算符函数的对象,也即即thisthis指针指向的对指针指向的对象。象。隐含参数隐含参数this指针指针,&,|,运运算不改变操作数的值。算不改变操作数的值。它们的计算结果产生它们的计算结果产生一个新的值,为此将一个新的值,为此将这几个函数的返回值这几个函数的返回值设置为设置为ByteByte。6.2 常用运算符重载二元运算符重载(成员函数方式)Byte&operator=(const Byte&right)/自赋值检测自赋值检测 if(this=&right)re
23、turn*this;b=right.b;return*this;Byte&operator+=(const Byte&right)b+=right.b;return*this;Byte&operator/=(const Byte&right)assert(right.b!=0);b/=right.b;return*this;Byte&operator=(const Byte&right)b=right.b;return*this;赋值运算符和复合赋值运赋值运算符和复合赋值运算符会改变左操作数的值。算符会改变左操作数的值。这意味着,赋值运算符函这意味着,赋值运算符函数和复合赋值运算符函数数和复合
24、赋值运算符函数会改变调用它们的对象的会改变调用它们的对象的值,也即值,也即thisthis指针指向的指针指向的对象的值对象的值。这些函数的返回值为这些函数的返回值为ByteByte类类型的引用。类类型的引用。隐含参数隐含参数this指针指针6.2 常用运算符重载二元运算符重载(成员函数方式)bool operator=(const Byte&right)const return b=right.b;bool operator!=(const Byte&right)const return b!=right.b;bool operator(const Byte&right)const retur
25、n b right.b;/二元逻辑运算符二元逻辑运算符&和和|bool operator&(const Byte&right)const return b&right.b;逻辑和关系运算符不会改逻辑和关系运算符不会改变操作数的值,它们的返变操作数的值,它们的返回值是回值是boolbool类型类型隐含参数隐含参数this指针指针6.2 常用运算符重载二元运算符重载(友员函数方式)class Integer long i;public:Integer(long ll=0):i(ll)/算术运算,按位与和移位运算符算术运算,按位与和移位运算符 friend const Integer operato
26、r+(const Integer&left,const Integer&right);friend const Integer operator-(const Integer&left,const Integer&right);friend const Integer operator&(const Integer&left,const Integer&right);friend const Integer operator *类型转换类型转换必须是成员函数必须是成员函数复合赋值运算符复合赋值运算符成员函数成员函数其他二元运算符其他二元运算符非成员函数非成员函数输入输出运算符输入输出运算符非成
27、员函数非成员函数#include using namespace std;class Number int i;public:Number(int ii=0):i(ii)const Number operator+(const Number&n)const return Number(i+n.i);int Getval()return i;Number operator-(Number n1,Number n2)return Number(n1.Getval()-n2.Getval();int main()Number a(47),b(11);a+b;a+1;1+a;a-1;return 0;
28、+运算符成员函数不能转换左操作数的类型。运算符成员函数不能转换左操作数的类型。带有一个参数的构造函数也是类型转换函数。带有一个参数的构造函数也是类型转换函数。6.3 输入输出运算符的重载输入输出运算符函数必须以友元或普通函数输入输出运算符函数必须以友元或普通函数形式重载形式重载(原因:它的左操作数必须是(原因:它的左操作数必须是io对对象)。象)。输入输出运算符函数的声明:输入输出运算符函数的声明:istream&operator(istream&,type&);ostream&operator(ostream&,const type&);istream 和和 ostream 是是 C+的预定
29、义流类。的预定义流类。cin 是是 istream 的对象,的对象,cout 是是 ostream 的对象。的对象。运算符运算符 由由 istream 重载为提取操作,用于输入基本类型数据重载为提取操作,用于输入基本类型数据6.3 输入输出运算符的重载class Vector public:Vector(int num=1);Vector(Vector&vect);int size();int at(int pos);bool set(int pos,int elem);void printAll();Vector&operator=(Vector&vec);int&operator(int
30、index);friend ostream&operator(istream&is,Vector&);Vector();private:int num;int*data;6.3 输入输出运算符的重载举例ostream&operator(ostream&os,Vector&vec)for(int i=0;ivec.num;i+)osvec.datai(istream&is,Vector&vec)for(int i=0;ivec.datai;return is;6.4 赋值运算符的重载与其它运算符相比,赋值运算符(与其它运算符相比,赋值运算符(=)的特)的特别之处是:别之处是:程序员没有定义赋值运
31、算符函程序员没有定义赋值运算符函数,编译器会为生成一个默认的赋值运算数,编译器会为生成一个默认的赋值运算符函数符函数。默认赋值运算符函数的函数体的内容即:把默认赋值运算符函数的函数体的内容即:把=右边右边对象的各成员的值赋给对象的各成员的值赋给=左边对象的各成员。左边对象的各成员。赋值运算符函数赋值运算符函数operator=必须是成员函数必须是成员函数6.4 赋值运算符的重载需要程序员自己定义赋值运算符函数的原因Vector&Vector:operator=(Vector&vect)num=vect.num;data=vect.data;return *this;编译器生成的默认赋值函数(以
32、编译器生成的默认赋值函数(以VectorVector类为例):类为例):上述代码会产生与默认拷贝构造函数相同的问题。上述代码会产生与默认拷贝构造函数相同的问题。6.4 赋值运算符的重载A.num=A.data=Vector A(5);Vector B=A;A:B:B.num=B.data=2000H2040Hint main()Vector A(5);Vector B=A;A.set(4,9);B=A;return 0;52040HVector:Vector(int num)this-num=num;data=new int num;for(int i=0;inum;i+)datai=0;52
33、000H00000Vector:Vector(Vector&vect)num=vect.num;data=new int num;for(int i=0;inum;i+)datai=vect.datai;000009A.num=A.data=Vector A(5);Vector B=A;A:B:B.num=B.data=2000H2040H2040H52000H00000000009int main()Vector A(5);Vector B=A;A.set(4,9);B=A;return 0;5Vector&Vector:operator=(Vector&vect)num=vect.num;
34、data=vect.data;return *this;52000H调用调用B.operator=(A)6.4 赋值运算符的重载自定义赋值运算符函数class Vector public:Vector(int num=1);Vector(Vector&vect);int size();int at(int pos);bool set(int pos,int elem);void printAll();Vector&operator=(Vector&vec);Vector();private:int num;int*data;声明赋值运算符函数声明赋值运算符函数6.4 赋值运算符的重载自定义赋值
35、运算符函数Vector&Vector:operator=(Vector&vec)if(this!=&vec)assert(vec.num=num);for(int i=0;inum;i+)datai=vec.datai;return *this;避免自复制避免自复制确保赋值的两个向量长度确保赋值的两个向量长度一致。一致。A.num=A.data=Vector A(5);Vector B=A;A:B:B.num=B.data=2000H2040H52040H52000H0000000009int main()Vector A(5);Vector B=A;A.set(4,9);B=A;return
36、 0;Vector&Vector:operator=(Vector&vec)if(this!=&vec)assert(vec.num=num);for(int i=0;i=0&indexnum);return dataindex;返回向量对象指定位置上的元素返回向量对象指定位置上的元素6.6 用户自定义类型转换数据类型转换在程序编译时或在程序运行实现数据类型转换在程序编译时或在程序运行实现基本类型基本类型 基本类型基本类型基本类型基本类型 类类型类类型类类型类类型 类类型类类型类对象的类型转换可由两种方式说明:类对象的类型转换可由两种方式说明:类对象的类型转换可由两种方式说明:类对象的类型转换
37、可由两种方式说明:构造函数构造函数构造函数构造函数转换函数转换函数转换函数转换函数 称为用户定义的类型转换或类类型转换称为用户定义的类型转换或类类型转换称为用户定义的类型转换或类类型转换称为用户定义的类型转换或类类型转换,有隐式调用和显式调用方式有隐式调用和显式调用方式有隐式调用和显式调用方式有隐式调用和显式调用方式 6.6 用户自定义类型转换构造函数做类型转换带单个参数的构造函数提供了参数类型的对象到本类型带单个参数的构造函数提供了参数类型的对象到本类型对象的转换。对象的转换。ClassX:ClassX(arg,arg1=E1,,argn=En);说明了一种从参数说明了一种从参数 argar
38、g 的类型到的类型到X类型的转换类型的转换6.6 用户自定义类型转换#include using namespace std;class Complexprivate:double re,im;public:Complex(int re):re(re),im(0)Complex(int re,int im):re(re),im(im)Complex operator+(Complex num2)double t1=re+num2.re;double t2=im+num2.im;return Complex(t1,t2);friend ostream&operator(ostream&os,Co
39、mplex&cm);ostream&operator(ostream&os,Complex&cm)oscm.re+cm.imi;return os;int main()Complex c(2,3),d(4,5);c=d+5;cout c endl;return 0;6.6 用户自定义类型转换带有一个参数的构造函数能将其它类型转换为它所在的类型,但不能把它所在的类的对象转换为其它类型。类类型转换函数类类型转换函数是一种特殊的成员函数,是一种特殊的成员函数,提供类对提供类对象之间显式类型转换的机制。象之间显式类型转换的机制。X:operator T()return T 类型的对象类型的对象 类外定
40、义类类型转换函数声明的语法形式:类外定义类类型转换函数声明的语法形式:T T 可以是预定义类型,也可可以是预定义类型,也可以是用户定义类型以是用户定义类型函数没有参数,没有返回类函数没有参数,没有返回类型,但必须有一条型,但必须有一条 return return 语句,返回语句,返回 T T 类型的对象类型的对象该函数只能为成员函数,不能为友元该函数只能为成员函数,不能为友元该函数只能为成员函数,不能为友元该函数只能为成员函数,不能为友元将将X类型转换为类型转换为T类型类型6.6 用户自定义类型转换#include#include using namespace std;class MinIn
41、t char m;public:/int类型转换为类型转换为MinInt MinInt(int val=0)assert(val=0&val=100);/要求取值范围在要求取值范围在0100之间之间 m=static_cast(val);/MinInt对象转换为对象转换为int 类型类型 operator int()return static_cast(m);int main()MinInt mi(10),num;num=mi+20;/*首先将首先将mi转换为转换为int类型,再执行加法运算;类型,再执行加法运算;再将再将int类型的计算结果类型的计算结果30 转换为赋值左边的转换为赋值左边的
42、MinInt 类型类型*/int val=num;/将将num自动转换为自动转换为int,并赋值给,并赋值给val cout mi t num t val;/num 和和mi 转换为转换为int输出输出 类内定义类型类内定义类型转换函数转换函数带单个参数的带单个参数的构造函数构造函数相当于调用:相当于调用:num.operator int();小结运运算算符符重重载载可可以以像像基基本本数数据据类类型型一一样样,用用简简洁洁明明确确的的运运算算符符操操作作自自定定义义的的类类对象。对象。重载运算符函数可以对运算符作出新的解释,但重原有的基本语义不变。重载运算符函数可以对运算符作出新的解释,但重
43、原有的基本语义不变。运算符函数既可以重载为成员函数,也可以重载义为友元函数或普通函数。运算符函数既可以重载为成员函数,也可以重载义为友元函数或普通函数。当当单单目目运运算算符符的的操操作作数数,或或者者双双目目运运算算符符的的左左操操作作数数是是该该类类的的一一个个对对象象时时,以以成成员员函函数数重重载载;当当一一个个运运算算符符的的操操作作需需要要修修改改类类对对象象状状态态时时,应应该该以以成成员员函数重载。如果以成友元函数重载,可以使用引用参数修改对象。函数重载。如果以成友元函数重载,可以使用引用参数修改对象。当当运运算算符符的的操操作作数数(尤尤其其是是第第一一个个操操作作数数)希希望望有有隐隐式式转转换换,则则重重载载算算符符时时必须用友元函数。必须用友元函数。构构造造函函数数和和类类型型转转换换函函数数可可以以实实现现基基本本类类型型与与类类类类型型,以以及及类类类类型型之之间间的的类类型转换。型转换。
限制150内