运算符重载
重载的运算符必须接受至少一个自定义类型。接受的参数都为内置类型的运算符无法被重载。
?
运算符作为类的成员函数被重载时,类的对象就作为第一个参数。注意此时函数的返回方式。
?
重载++a会调用operator++(a),重载a++会调用operator++(a, int),其中第二个int参数是不会被用到的,只是用来区分前缀和后缀调用。--的重载也是一样。
?
=和[]只能作为成员函数被重载。()只能作为成员函数被重载,可以带任意多个参数。(若可以不作为成员函数被重载,则对于内置类型的运算就可以被重载,这是没有意义的)
->和->*也只能作为成员函数被重载,但对返回值有一定的限制。
?
.和.*不能被重载
?
返回值优化:
Integer tmp(left.i + right.i);
return tmp;
?
这样编译器需要三步才能完成(构造,拷贝,析构),而return Integer(left.i + right.i);则只需要一步
重载时作为成员或非成员函数的选择:
所有的一元运算符 推荐作为成员
= () [] -> ->* 必须作为成员
+= -= /= *= ^=
&= |= %= >>= <<= 推荐作为成员
所有其他的二元运算符 推荐作为非成员
?
当对象还没有被创建时,=调用的是构造函数或拷贝构造函数,为的是初始化对象;当对象已被创建时,=调用的才是operator=。因此
Fee fee(1);
Fee fum(fi);
这样的写法要比
Fee fee = 1;
Fee fum = fi;
这样的写法清晰。
?
在重载赋值运算符时,首先检查是否是对自身赋值是个好习惯。
?
当对象中有指针时,拷贝构造函数通常需要连同复制出指针所指向的内容。而当此内容很大时,通常采用引用计数的方法,只在需要修改数据且引用数大于1时才复制内容。这种技术被称为copy-on-write。
?
当构造函数接受一个其他类型的对象作为参数时,编译器可以用它来进行自动类型转换。如果不需要这样的自动转换,在构造函数前加上explicit。
也可以重载operator 类型名来定义自动类型转换。由于这种类型转换是由源对象完成的(不像构造函数的类型转换是由目标对象完成的),因此可以完成自定义对象到内置类型的转换。
?
运算符重载为非成员函数时,运算符两边都可以进行自动类型转换。
提供自动类型转换时注意两种类型之间只需提供一条转换路径,否则会出现二义性错误。
?
?
#include
using namespace std;
template
class Array { public: // 重载[]运算符 T& operator [] (size_t num) { return m_arr[num]; } // 提供一个常版本的[]运算符 T const& operator [] (size_t num) const { // 为了维护方便,尽量复用函数 return const_cast
(*this)[num]; } int length(void) const { return S; } // 由于左操作数是标准提供的类,最好用友元的方式实现<<重载 friend ostream& operator << (ostream& os, Array const& arr) { for (size_t i = 0; i < S; ++i) cout << arr[i] << ' '; cout << endl; } private: T m_arr[S]; };
?
?