310 likes | 457 Views
第十六章 运算符重载. 16.1 运算符重载的需要性 16.2 如何重载运算符 16.3 值返回与引用返回 16.4 运算符作成员函数 16.5 重载增量运算符. 16.1 运算符重载的需要性. C++ 认为: ( 1 )用户定义的数据类型就像基本数据类型 int 和 char 一样有效。 ( 2 )运算符是为基本数据类型定义的,应允许使之适用于用户定义类型。 ( 3 )运算符重载可以改进可读性,但 不是非有不可 。. 16.1 运算符重载的需要性 ( 续 ). 例: class A {public: A(int x){a=x;}
E N D
第十六章 运算符重载 16.1 运算符重载的需要性 16.2 如何重载运算符 16.3 值返回与引用返回 16.4 运算符作成员函数 16.5 重载增量运算符
16.1 运算符重载的需要性 C++认为: (1)用户定义的数据类型就像基本数据类型int和char一样有效。 (2)运算符是为基本数据类型定义的,应允许使之适用于用户定义类型。 (3)运算符重载可以改进可读性,但不是非有不可。
16.1 运算符重载的需要性(续) 例: class A {public: A(int x){a=x;} //… }; A a(5),b(10),c; c=a+b;
第十六章 运算符重载 16.1 运算符重载的需要性 16.2 如何重载运算符 16.3 值返回与引用返回 16.4 运算符作成员函数 16.5 重载增量运算符
16.2 如何重载运算符 说明: (1)运算符是在C++系统内部定义的,具有特定语法规则,如参数说明,运算顺序,优先级等。 (2)重载运算符时,要注意该重载运算符的运算顺序和优先级不变。 (3)运算符是函数,除了运算顺序和优先级不能更改外,参数和返回类型是可以重新说明的,即可以重载。
16.2 如何重载运算符(续1) 重载形式: 返回类型 operator运算符号(参数说明); //单目、双目 例:A类对象加法 class A{}; int operator+(A&,A&); //两个A类对象参加运算,返回int型值。
16.2 如何重载运算符(续2) 注意: (1)C++规定:运算符中参数说明都是内部类型时,不能重载。 原因:C++基本数据类型之间的关系是确定的,如果允许定义其上的新操作,那么,基本数据类型的内在关系将混乱。 (2)C++规定:“. :: .* .-> ?:”这五个运算符不能重载,也不能创造新运算符。
例:将运算符+和++声明为人民币类的友元。 //ch18-2 #include<iostream.h> class RMB {public: RMB(unsigned int d,unsigned int c); friend RMB operator+(RMB&,RMB&); friend RMB& operator++(RMB&); void display() {cout<<(yuan+jf/100.0)<<endl; } protected: unsigned int yuan; unsigned int jf; };
例: 续1 RMB::RMB(unsigned int d,unsigned int c) //构造函数 {yuan=d; jf=c; while(jf>=100) {yuan++; jf-=100; } } RMB operator+(RMB& s1,RMB& s2) //运算符重载,值返回 {unsigned int jf=s1.jf+s2.jf; unsigned int yuan=s1.yuan+s2.yuan; RMB result(yuan,jf); return result; }
例: 续2 RMB& operator++(RMB& s) //运算符重载,引用返回 {s.jf++; if(s.jf>=100){s.jf-=100; s.yuan++; } return s; } void main() {RMB d1(1,60); RMB d2(2,50); RMB d3(0,0); d3=d1+d2; ++d3; d3.display(); } 结果:4.11
16.2 如何重载运算符(续3) 说明: (1)operator+()和operator++()定义为友元是为了能访问人民币类的保护成员。 (2)operator+()是一个双目运算符,它有两个参数s1和s2,并且相加的结果仍为人民币类,返回人民币类对象。 (3)operator++()是单目运算符,它含有一个参数。operator++()对人民币类对象的角分做加1运算,如果它超过100,则对该对象的元做加1运算并使角分为0。 (4)如果只给出一个operator++()定义,那么它一般可用于前缀后缀两种形式。即d3++与++d3不作区别。
第十六章 运算符重载 16.1 运算符重载的需要性 16.2 如何重载运算符 16.3 值返回与引用返回 16.4 运算符作成员函数 16.5 重载增量运算符
16.3 值返回与引用返回 问题:上节例题中,为什么operator+()由值返回,而operator++()由引用返回呢? 解决:重载定义+和++操作的意义是人为的,返回类型应根据实际情况。 (1)operator+():两个对象相加,不改变其中任一个对象。而且它必须生成一个结果对象来存放加法的结果,并将该结果对象以值的方式返回给调用者。 (2)operator++():修改了它的参数,而且其返回值要求是左值,这个条件决定了它不能以值返回,而是以引用返回。
第十六章 运算符重载 16.1 运算符重载的需要性 16.2 如何重载运算符 16.3 值返回与引用返回 16.4 运算符作成员函数 16.5 重载增量运算符
16.4 运算符作成员函数 说明: (1)一个运算符既可以作为一个非成员函数实现,还可以作为一个成员函数实现。 (2)作为成员的运算符比之作为非成员的运算符,在声明和定义时,形式上少一个参数。这是由于C++对所有的成员函数隐藏了第一个参数this。 (3)一个运算符成员形式,将比非成员形式少一个参数,左边参数是隐含的。
例:改写ch18_2,将+和++运算符改为以成员函数形式实现。例:改写ch18_2,将+和++运算符改为以成员函数形式实现。 //ch18_3.cpp #include<iostream.h> class RMB {public: RMB(unsigned int d,unsigned int c); RMB operator +(RMB&); RMB operator ++(); void display() {cout<<(yuan+jf.100.0)<<endl; } protected: unsigned int yuan; unsigned int jf; }
例: 续1 RMB:: RMB(unsigned int d,unsigned int c) {yuan=d; jf=c; while(jf>=100){yuan++; jf-=100; } } RMB RMB::operator+(RMB& s) {unsigned int c=jf+s.jf; unsigned int d=yuan+s.yuan; RMB result(d,c); return result; } RMB& RMB::operator++() {jf++; if(jf>=100){jf-=100; yuan++; } return *this; }
例: 续2 void main() {RMB d1(1,60); RMB d2(1,60); RMB d3(0,0); d3=d1+d2; ++d3; d3.display(); }
第十六章 运算符重载 16.1 运算符重载的需要性 16.2 如何重载运算符 16.3 值返回与引用返回 16.4 运算符作成员函数 16.5 重载增量运算符
16.5 重载增量运算符 主要内容: 1.前增量与后增量的区别 2.成员形式的重载 3.非成员形式重载
1.前增量与后增量的区别 (1)使用前增量时,对对象进行增量修改,然后再返回该对象。所以前增量运算符操作时,参数与返回的是同一个对象。这与基本数据类型的前增量操作类似,返回的也是左值。 (2)使用后增量时,必须在增量之前返回原由的对象值。为此,需要创建一个临时对象,存放原有的对象,以便对操作数进行增量修改时,保存最初的值。后增量操作返回的是原有对象值,不是原有对象,原有对象已经被增量修改,所以,返回的应该是存放原由对象值的临时对象。
2.成员形式的重载 C++约定:在增量运算符定义中,放上一个整数形参,就是后增量运算符。
例:分别定义了前增量与后增量成员运算符。 //ch18_4.cpp #include<iostream.h> class Increase {public: Increase(int x):value(x){} Increase& operator++(); //前增量,引用返回 Increase operator++(int); //后增量,值返回 void display() {cout<<”the value is”<<value<<endl; } private: int value; }
例: 续1 Increase& Increase::operator++() {value++; //先增量 return *this; //再返回原对象 } Increase Increase::operator++(int) {Increase temp(*this); //临时对象存放原有对象值 value++; //原有对象增量修改 return temp; //返回原有对象值 }
例: 续2 void main() {Increase n(20); n.display(); (n++).display(); n.display(); ++n; n.display(); ++(++n); n.display(); (n++)++; n.display(); }
例: 续3 结果: the value is 20 the value is 20 the value is 21 the value is 22 the value is 24 the value is 25 小结: (1)前后增量操作的意义,决定了其不同的返回方式。前增量运算符返回引用,后增量运算符返回值。 (2)后增量运算符中的参数int只是为了区别前增量与后增量,除此之外没有任何作用。
3.非成员形式的重载 说明:前增量和后增量的非成员运算符,也有类似的编译区分方法。
例:将ch18_4.cpp中的前增量和后增量运算符修改为非成员形式。例:将ch18_4.cpp中的前增量和后增量运算符修改为非成员形式。 //ch18_5.cpp #include<iostream.h> class Increase {public: Increase(int x):value(x){} friend Increase& operator++(Increase&); //前增量,引用返回 friend Increase operator++(Increase&,int); //后增量,值返回 void display() {cout<<”the value is”<<value<<endl; } private: int value; }
例: 续1 Increase& operator++(Increase& a) {a.value++; return a; } Increase operator++(Increase&a,int) {Increase temp(*a); a.value++; return temp; } void main(){//同上 } 结果:同上 小结: (1)前增量和后增量运算符的定义以及成员形式与非成员形式稍有不同; (2)前增量和后增量运算符的使用完全不同。
小结 使用运算符重载可以使程序易于理解并易于对对象进行操作。几乎所有的C++运算符都可以被重载,但应注意不要重载违反常规的运算符。不能改变运算拊操作数的数量,也不能发明新运算符。 如果在类中没有说明本身的拷贝构造函数和赋值运算符,编译程序将会提供,但它们都只是对对象进行成员浅拷贝。在那些以指向堆空间指针作为数据成员的类中,必须避免使用浅拷贝,而要为类定义自己的赋值运算符,以给对象分配堆内存。 this指针指向当前的对象,它是所有成员函数的不可见的参数,在重载运算符时,经常返回this指针的间接引用。
小结(续) 通过转换运算符可以在表达式中使用不同类型的对象。转换运算符不遵从函数应有返回值类型的规定,与构造函数的析构函数相同,它没有返回值。 在前增量和后增量运算符定义中,使用int形参只是为了标志前后有别,没有其它作用。 拷贝构造函数用已存在的对象创建一个相同的新对象。而赋值运算符把一个对象的成员变量值赋予一个已存在的同类对象的同名变量。