C++ 运算符重载
运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。你可以重定义或重载大部分 C++ 内置的运算符。例如 + 、 - 、 * 、 / 、++、--、>>、<<等,这样,你就能使用自定义类型的运算符。
基本原则
1、我们只能重载已有的运算符,而无权发明新的运算符;对于一个重载的运算符,其优先级和结合律与内置类型一致才可以;不能改变运算符操作数个数;
2、. :: ?: sizeof typeid **不能重载;
3、两种重载方式,成员运算符和非成员运算符,成员运算符比非成员运算符少一个参数;下标运算符、箭头运算符必须是成员运算符;
4、引入运算符重载,是为了实现类的多态性;
5、当重载的运算符是成员函数时,this绑定到左侧运算符对象。成员运算符函数的参数数量比运算符对象的数量少一个;至少含有一个类类型的参数;
6、从参数的个数推断到底定义的是哪种运算符,当运算符既是一元运算符又是二元运算符(+,-,*,&);
7、下标运算符必须是成员函数,下标运算符通常以所访问元素的引用作为返回值,同时最好定义下标运算符的常量版本和非常量版本;
8、箭头运算符必须是类的成员,解引用通常也是类的成员;重载的箭头运算符必须返回类的指针;
运算符重载的基本格式
重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和
其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个
返回类型和一个参数列表。
Point operator+(const Point &);
运算符重载有两种方式:一种是类内重载(运算符重载函数作为类的成员函数),另一种是类外重载(运算符重载函数作为类的友元函数)
类内重载
#include <iostream> using namespace std; class Point{ public: Point(){}; Point (int x, int y): x(x),y(y) {}; Point operator+(const Point &a){ //类内重载,运算符重载函数作为类的成员函数 Point ret; ret.x = this->x + a.x; ret.y = this->y + a.y; return ret; } int x,y; }; int main() { Point a(2,4),b(5,3); Point c = a + b; cout<< "x :" << c.x << endl; cout<<"y :" << c.y << endl; }
当上面的代码被编译和执行时,它会产生下列结果:
x : 7
y: 7
运算符重载是类内重载时,运算符重载函数作为类的成员函数,以上述代码为例 a + b 相当于 a 对象调用+方法并且传入参数是 b 对象
类外重载
#include <iostream> using namespace std; class Point{ public: Point(){}; Point (int x, int y): x(x),y(y) {}; friend Point operator+(const Point &, const Point &); int x,y; }; Point operator+(const Point &a,const Point &b){//类外重载,运算符重载函数作为类的友元函数 Point ret; ret.x = a.x + b.x; ret.y = a.y + b.y; return ret; } int main() { Point a(2,4),b(5,3); Point c = a + b; cout<< "x :" << c.x << endl; cout<<"y :" << c.y << endl; }
当上面的代码被编译和执行时,它会产生和上面一样的结果
各种运算符重载实例
下面将进行各种运算符重载实例的代码演示,演示几种基本的运算符重载。
插入运算符重载>> and 提取运算符重载<<
以提取运算符重载<<
为例,cout
是 ostream
类的对象。ostream
类和 cout
都是在头文件 <iostream>
中声明的。ostream
类将<<
重载为成员函数。
下面我们重载<<
使用cout
输出a对象
#include <iostream> using namespace std; class Point{ public: Point(){}; Point (int x, int y): x(x),y(y) {}; friend Point operator+(const Point &, const Point &); friend ostream &operator<<(ostream &out , const Point &a); private: int x,y; }; Point operator+(const Point &a,const Point &b){ Point ret; ret.x = a.x + b.x; ret.y = a.y + b.y; return ret; } ostream &operator<<(ostream &out , const Point &a){ out << "<Point>( " << a.x << ", " << a.y << ")"; return out; } int main() { Point a(2,4),b(5,3); Point c = a + b; cout << c<< endl; }
当上面的代码被编译和执行时,它会产生下列结果:
< Point>( 7, 7)
注意:重载<<
时,是类外重载,习惯上人们是使用cin>>
和 cout<<
的,得使用友元函数来重载运算符,如果使用成员函数来重载会出现 c<<cout;
这种不自然的代码。
另外应该会有人对ostream &operator<<(ostream &out , const Point &a)
函数感到疑惑,首先在重载<<
时,返回值类型是ostream&
, 第一个参数也是ostream&
。也就是说,表达式cout<<c
的返回值仍是 cout
,所以cout<<c<<endl;
才能成立
前置运算符重载++ and 后置运算符重载++
#include <iostream> using namespace std; class Point{ public: Point(){}; Point (int x, int y): x(x),y(y) {}; friend Point operator+(const Point &, const Point &); friend ostream &operator<<(ostream &out , const Point &a); Point& operator++(){ //前置运算符,需要引用返回,不需要参数。返回自增后的值,且返回的是一个左值 x++; y++; return *this; } const Point operator++(int){//后置++,不需要引用返回,需要参数区分。返回自增前的值,且返回的是一个右值 Point temp(x,y); x++; y++; return temp; } private: int x,y; }; Point operator+(const Point &a,const Point &b){ Point ret; ret.x = a.x + b.x; ret.y = a.y + b.y; return ret; } ostream &operator<<(ostream &out , const Point &a){ out << "<Point>(" << a.x << " , " << a.y << ")"; return out; } int main() { Point a(2,4),b(5,3); Point c = a + b; cout << c << endl; c++; cout << c << endl; ++c; cout << c << endl; }
当上面的代码被编译和执行时,它会产生下列结果:
(7 , 7)
< Point>(8 , 8)
< Point>(9 , 9)
1>为区别前置和后置运算符,需要在后置运算符重载函数中加参数“int”,虽然这个类型在此除了以示区别之外并不代表任何实际含义;
2>前置返回的是变量的引用,后置返回的是常量。所以++++c合法,而c++++不合法;
3>为什么不让c++++也合法呢?如果要实现c++++合法,必须使后置返回变量或变量的引用。c++是先返回c值再+1,所以不可能返回c,那就只能先建立局部变量来保存c的初值,然后再返回局部变量(局部变量不允许返回引用),但返回了局部变量之后,如果再连着进行下一次++运算,参与运算的就是这个局部变量的值了,所以此时c++++其实等效与c++,也就没有存在的意义了。