3.运算符重载
一、操作符函数
在C++中,编译器有能力把一个由数据、对象和操作符共同组成的表达式,解释为对一个全局或成员函数的调用。
该全局或成员函数被称为操作符函数,通过重定义操作符函数,可以实现针对自定义类型的运算法则,并使之与内置类型一样参与各种表达式。
二、双目操作符表达式
成员函数
形如L#R双目操作符表达式,将被编译器解释为 L.operator#(R)
a-b+c == a.operator-(b).operator+(c)
全局函数
形如L#R的双目操作符表达式,将被编译器解释为 ::operator#(L,R)
a-(b+c) == ::operator-(a,::operator+(b,c))
三、单目操作符表达式
成员函数
形如#O或O#的单目操作表达式,将被编译器解释为 O.operator#(),唯一的操作数是调用对象。
全局函数
形如#O或O#的单目操作表达式,将被编译器解释为 ::operator#(O),唯一的操作数是调用对象。
以下所有重载的代码实例
1 #include <iostream> 2 using namespace std; 3 4 5 6 struct Point 7 { 8 int x; 9 int y; 10 11 public: 12 Point(int _x=0,int _y=0) 13 { 14 x = _x; 15 y = _y; 16 } 17 18 Point(Point &that) 19 { 20 x = that.x; 21 y = that.y; 22 } 23 24 Point &operator = (Point &that) 25 { 26 x = that.x; 27 y = that.y; 28 } 29 30 void show() 31 { 32 cout << "x=" << x << "," << "y=" << y << endl; 33 } 34 35 Point operator - (Point &that) 36 { 37 Point t; 38 t.x = x-that.x; 39 t.y = y-that.y; 40 return t; 41 } 42 43 Point operator +(Point &that) 44 { 45 Point t; 46 t.x = x+that.x; 47 t.y = y+that.y; 48 return t; 49 } 50 51 /* 52 53 Point& operator --(void) 54 { 55 --x; 56 --y; 57 return *this; 58 } 59 60 61 Point operator --(int) 62 { 63 Point t(*this); 64 --x; 65 --y; 66 return t; 67 } 68 69 70 */ 71 72 int operator [](int index) 73 { 74 return !index ?x:y; 75 } 76 77 /* 78 Point operator *(Point &that) 79 { 80 Point t; 81 t.x = x*that.x; 82 t.y = y*that.y; 83 return t; 84 } 85 86 */ 87 friend Point operator %(Point &p1,Point &p2); 88 friend Point operator *(Point &p1,Point &p2); 89 friend Point &operator --(Point &p1); 90 friend Point operator --(Point &p1,int); 91 friend istream & operator >> (istream &is,Point &p1); 92 93 94 }; 95 96 97 98 Point operator %(Point &p1,Point &p2) 99 { 100 Point p3(p1.x%p2.x,p1.y%p2.y); 101 return p3; 102 } 103 104 Point operator *(Point &p1,Point &p2) 105 { 106 cout << "我是友元" << endl; 107 Point p3(p1.x*p2.x,p1.y*p2.y); 108 return p3; 109 } 110 111 112 Point &operator --(Point &p1) 113 { 114 --p1.x; 115 --p1.y; 116 return p1; 117 } 118 119 Point operator --(Point &p1,int) 120 { 121 Point t(p1); 122 --p1.x; 123 --p1.y; 124 return t; 125 } 126 127 128 istream & operator >> (istream &is,Point &p1) 129 { 130 return is >> p1.x >> p1.y; 131 } 132 133 134 135 136 int main() 137 { 138 Point p1(1,2); 139 p1.show(); 140 Point p2(2,3); 141 p2.show(); 142 143 144 Point p3; 145 cin >> p3; 146 p3.show(); 147 cout << p3[0] << p3[1] << endl; 148 149 }
四、典型的双目运算符重载
成员函数
1 Point operator /+-*%|^& (Point& that) 2 { 3 Point t; // 会调用无参构造 4 t.x = x / that.x; 5 t.y = y / that.y; 6 return t; // 不能返回局部对象的引用,否则会出现悬空引用 7 }
注意:原对象的值不变,要产生一个临时的对象
1 bool operator > < >= <= == != || && (Point& that) 2 { 3 4 } 5 6 Point& operator += -= *= /= (Point& that) 7 { 8 9 return *this; 10 }
注意:运算符的重载要符合情理。
全局函数
可能会访问到参数的私有成员:
1、把成员变成公开,但会破坏类的封闭性。
2、把全局函数声明为友元(友元不是成员),
3、不能在友元函数中直接访问成员变量。
1 Point operator + (Point& a,Point& b) 2 { 3 Point t(a.x+b.x,a.y+b.y); 4 return t; 5 }
五、典型的单目运算符重载
成员函数:
前++/--
1 Point& operator ++/-- (void) 2 { 3 4 }
后++/--
1 Point operator ++/-- (int) 2 { 3 4 }
全局函数:
前++/--
1 Point& operator ++/-- (Point&) 2 { 3 4 } 5
后++/--
1 Point operator ++/-- (Point&,int) 2 { 3 4 } 5
六、输入、输出运算符重载
输入、输出运算符不能重载为成员函数,只能是友元。
1 ostream& operator << (ostream& os,Point& p) 2 { 3 4 } 5 6 istream& operator >> (istream& is,Point& p) 7 { 8 9 }
七、特殊的运算符的重载
[] 下标运算符,可以把对象当作数组来使用。
() 函数运算符,可以把对象当作函数来使用。
-> 成员访问运算符,可以把对象当作指针来使用。
* 解引用运算符,可以把对象当作指针来使用。
new/delete 也可以进行重载,但不建议使用。
new会自动调用重载的new函数再构造函数。
delete会先调用析构再调用重载的delete函数。
只有极个别的运算符的重载对于对象来说是有意义(>>,<<)
常考的运算符重载:前++/--,后++/--
八、运算符重载的一些限制
1、不能重载的运算符
:: 作用域限定符
. 成员访问运算
.* 成员指针解引用
?: 三目运算符
sizeof 字节长度运算符
typeid 类型信息操作符
2、运算符的重载改变不了运算符的优先级
3、无法改变运算符的操作个数
4、无法发明新的运算符
5、重载运算符要注意运算符的一致性
不要改变运算符默认的运算规则
6、运算符的重载是为了方便使用、增强可读,不应该成功卖弄的工具。