[cpp] 重载运算符规律总结
重载运算符是对正常函数的语法美化.没给语言增加任何基本的东西,但改善了可理解性并降低维护费用.当用户需要时,就应该使用运算符重载,但应该仅仅以用户熟悉的语义方式来使用它。
1. 重载规则
不能重载的运算符: . 和 .* 和 ?: 和 :: 和 sizeof 和 typeid
重载运算符有两种基本选择: 类的成员函数或者友元函数, 建议规则如下:
运算符 |
建议使用 |
所有一元运算符 |
成员函数 |
= () [] -> |
必须是成员函数 |
+= -= /= *= ^= &= != %= >>= <<= , 似乎带等号的都在这里了. |
成员函数 |
所有其它二元运算符, 例如: –,+,*,/ |
友元函数 |
2. 参数和返回值
当参数不会被改变,一般按const引用来传递(若是使用成员函数重载,函数也为const).
对于返回数值的决定:
1) 如果返回值可能出现在=号左边, 则只能作为左值, 返回非const引用。
2) 如果返回值只能出现在=号右边, 则只需作为右值, 返回const型引用或者const型值。
3) 如果返回值既可能出现在=号左边或者右边, 则其返回值须作为左值, 返回非const引用。
3. 几个例子
3.1 二元运算法建议使用友元函数重载,与内部类型的操作相似
1: class Integer {
2: int _val;
3: public:
4: Integer(int val = 0) : _val(val) {}
5:
6: // 二元运算符重载为成员函数
7: const Integer operator+(const Integer& i) const {
8: return Integer(_val + i._val);
9: }
10: // 二元运算符重载为友元函数
11: friend const Integer operator-(const Integer& ,const Integer&);
12: };
13: const Integer operator-(const Integer& l,const Integer& r) {
14: return Integer(l._val-r._val);
15: }
16:
17: Integer a(40), b(12);
18:
19: a+b;
20: a+1; // 正确, 左操作数为Integer对象, +按照Integer的成员函数解析右操作数为1, 进行自动类型转换
21: 1+a; // 错误, 左操作数为1, +按照常规操作符解析, 而右操作符为Integer对象,1无法进行转化
22: a-b; // 正确
23: a-1; // 正确
24: 1-a; // 正确, 左操作数为1, 而右操作符为Integer对象,-作为Integer的一个友元函数,1被转化为Integer对象
1) 在上面的代码中, 二元操作符+作为成员函数重载,在进行形如1+a之类的调用无法正确解析。二元操作符-作为友元函数重载,使用方法与常规的-号操作符的操作类似。
2) 如上的运算符重载, 运算符的运算结果必定位于=号的右边, 返回的是一个右值, 返回const型值。
3.2 ++与--运算符重载
1) operator++有两种形式, 后缀形式i++, 它重载时有一类型为int的虚参。前缀形式++i,它重载时没有虚参.operator--情况类似。
2) 后缀形式(i++,i--)返回原状态的拷贝(或者返回void), 前缀形式(++i, --i)通过引用返回*this。这是为了和内部类型保持一致.
前缀版本(++i,--i)返回的是一个左值, 也就是返回一个非const引用.
后缀版本(i++,i--)返回的是一个右值, 也就是返回一个const型值
1: class Example{
2: public:
3: Example(int i,int j) { _x = i; _y = j;}
4: // 前缀形式(++i)重载的时候没有虚参,通过引用返回*this,也就是返回变化之后的数值
5: const Example& Example::operator++ () {
6: ++_x;
7: ++_y;
8: return *this;
9: }
10: // 后缀形式(i++)重载的时候有一个int类型的虚参, 返回原状态的拷贝
11: const Example Example::operator++ (int) {
12: Example tmp(*this);
13: ++_x;
14: ++_y;
15: return tmp;
16: }
17: int _x, _y;
18: };
19:
3.3 重载下标运算符[]
1: class Array {
2: public:
3: Array(int size) : _size(size) { _val = new int[_size];}
4: int& operator[] (int index) { return _val[index]; }
5: const int& operator[] (int index) const { return _val[index]; }
6: private:
7: int _size;
8: int* _val;
9: };
10: Array array_a(10);
11: array_a[0] = 1; // []的重载版本有非const版本
3.4 重载输入输出操作符
由于>>与<<操作符总是要被赋值,必须返回一个左值。
1: class A
2: {
3: private:
4: int a,b;
5: public:
6: A(int na = 0, int nb = 0):a(na), b(nb){}
7: friend istream& operator>>(istream& is, A& aa);
8: friend ostream& operator<<(ostream& os, const A& aa);
9:
10: };
11: ostream& operator<<(ostream& os, const A& aa) {
12: os << aa.a << " " << aa.b;
13: return os;
14: }
15:
16: istream& operator>>(istream& is, A& aa) {
17: is >> aa.a >> aa.b;
18: return is;
19: }