## 一.总则
1. 对于类类型,重载运算符一般使用 **引用** 作为参数,来避免不必要的复制。
2. 为了增加对 **常对象** 的支持,建议将 类类型参数 设置为 **常引用** ,对于在类内重载的运算符,可以将该函数设置为 **常成员函数** 。
3. 返回值不一定是 **引用** ,更不能是局部变量的引用(除了 **引用参数** )。
## 二.重载算术运算符(位运算符类似)
1. 算术运算符的操作细节:将计算结果放入新的对象,并返回。 **注意不要返回引用。**
2. 一般将双目算术运算符重载为友元或普通函数,将单目算术运算符重载为成员函数。
3. 一般情况下,算术运算符中 `+` 和 `*` 需要满足不同类型之间的交换律。为了满足这个需求,一般需要:
+ 重载为友元或普通函数。因为将这些运算符重载为普通函数,要求第一个操作数必须是该类的对象。
+ 添加 **转换构造函数** ,使得其他类型的数据可以转换到该类。
```c++
//重载示例
T1 operator+(const T1&,const T2&);
T1 operator+(const T2&,const T1&);
//如果你的类有转换构造函数,可以把T2 转换成 T1,也可以这么写:
T1 operator+(const T1&,const T1&);
```
4. 注意除法和取余中,第二个操作数为 `0` 的情况。
## 二.重载赋值运算符
1. 为满足 **链式调用** 的需求,应该设置返回值为第一个操作对象的引用。
2. 只能将该运算符重载为成员函数。
3. 一般不需要定义常成员函数版本。你会对一个常量赋值嘛?
```c++
//链式调用
a=b=c=d=e;
//拷贝赋值运算符重载示例
T& T::operator=(const T&);
//[11+][$]移动赋值运算符重载示例
T& T::operator=(const T&&);
```
## 三.重载复合赋值运算符
1. 复合赋值运算符的操作细节:将计算结果放入第一个运算对象,并返回 **其引用** 。
2. 一般将复合赋值运算符重载为成员函数。
3. 注意除法和取余中,第二个操作数为 `0` 的情况。
4. 一般不需要定义常成员函数版本。你会对一个常量赋值嘛?
```c++
//链式调用
a+=b;
//重载示例
T& T::operator+=(const T2&);
```
## 四.重载关系运算符
1. 因为这些运算符功能几乎差不多,因此可以先写一个专用函数用于比大小。
例如,大于返回1,等于返回0,小于返回 -1。
然后这些重载函数的内容基本上就是一句话的事。
2. 返回值应该为 `bool` 。
```c++
int T::compare(const T&) const;
bool operator>(const T& t1,const T& t2)
{
return t1.compare(t2) > 0;
}
bool operator<(const T& t1,const T& t2)
{
return t1.compare(t2) < 0;
}
bool operator==(const T& t1,const T& t2)
{
return t1.compare(t2) == 0;
}
```
## 五.重载前置递增递减运算符
1. 一般类内重载前置递增递减运算符,不需要伪参数。
2. **需要返回递增后自身的引用** 。
3. 一般不需要定义常成员函数版本。你会对一个常量递增递减嘛?
```c++
//重载
T& T::operator++();
T& T::operator--();
//调用
T i;
++i;
--i;
```
## 六.重载后置递增递减运算符
1. 一般类内重载后置递增递减运算符。
2. 为了区分前置递增递减运算符,需要加上一个 **伪参数** 。
3. **需要返回递增递减前的自身** 。
4. 一般不需要定义常成员函数版本。你会对一个常量递增递减嘛?
```c++
//返回递增递减前的自身对象
T T::operator++(int);
T T::operator--(int);
//调用
T i;
i++;
i--;
```
## 七.重载数组下标运算符
1. 只能重载为成员函数。
2. 可以通过赋值语句来修改运算结果并影响到对象自身,因此需要返回 **引用** 。
3. 注意检查下标范围。
```c++
T& T::operator[](int);
const T& T::operator[](int) const;
```
## 八.重载解引用运算符
1. 运算结果为一个 **左值** ,因此需要返回引用。
```c++
T& T::operator*();
const T& T::operator*() const;
```
## 九.重载指针的成员运算符
1. 该运算符非常特殊,虽然它是双目运算符,但它的重载函数 **没有参数**。
2. 返回值为一个可以进行 **指针的成员访问** 的指针。
3. 必须在类内重载。
```c++
//注: T1* 可以进行 `->` 操作
T1* T::operator->();
const T1* T::operator->() const;
//相当于: t1.operator->()->t2;
t1->t2;
```
## 十.重载函数调用运算符
1. 效果:可以像函数一样使用对象。
2. 只能在类内重载。
```c++
int T::operator()(int i,double d);
```
## 十一.重载插入和提取运算符
只能在类外重载。
```c++
ostream& operator<<(ostream& os,const T& obj);
istream& operator>>(istream& is,T& obj);
```
## 十二.罕见的运算符重载
1. `&(取地址)` 没有必要重载,因为它可以作用于任何类型的左值,表示取地址。
2. `,(逗号)` 可能会改变运算符本身的求值顺序。重载有负作用。
3. **逻辑运算符** 会失去其短路求值的特性。考虑到其负作用,一般使用类类型到 `bool` 的类型转换来代替逻辑运算符的重载。
4. `->*(指针的成员指针)` 。没有什么问题,但很少有类使用它。
- 阅读说明
- 1.1 概述
- C++基础
- 1.2 变量与常量
- 1.2.1 变量
- 1.2.2 字面值常量
- 字符型常量
- 数值型常量
- 1.2.3 cv限定符
- 1.3 作用域
- 1.3.1 标识符
- 1.3.2 *命名空间
- 1.3.3 作用域
- 1.3.4 可见性
- 1.4 数据类型
- 1.4.1 概述
- 1.4.2 处理类型
- 类型别名
- * auto说明符
- * decltype说明符
- 1.4.3 数组
- 1.4.4 指针
- 1.4.5 引用
- 1.5 表达式
- 1.5.1 概述
- 1.5.2 值的类别
- 1.5.3 *初始化
- 1.5.4 运算符
- 算术运算符
- 逻辑和关系运算符
- 赋值运算符
- 递增递减运算符
- 成员访问运算符
- 位运算符
- 其他运算符
- 1.5.5 *常量表达式
- 1.5.6 类型转换
- 第2章 面向过程编程
- 2.1 流程语句
- 2.1.1 条件语句
- 2.1.2 循环语句
- 2.1.3 跳转语句
- 2.1.4 *异常处理
- 2.2 函数
- 2.2.1 概述
- 2.2.2 函数参数
- 2.2.3 内置函数
- 2.2.4 函数重载
- 2.2.5 * 匿名函数
- 2.3 存储和生命期
- 2.3.1 生命周期与存储区域
- 2.3.2 动态内存
- 2.4 *预处理命令
- 第3章 面向对象编程
- 3.1 概述
- 3.2 类和对象
- 3.3 成员
- 3.3.1 访问限制
- 3.3.2 常成员
- 3.3.3 静态成员
- 3.3.4 成员指针
- 3.3.5 this指针
- 3.4 特殊的成员函数
- 3.4.1 概述
- 3.4.2 构造函数
- 3.4.3 析构函数
- 3.4.4 拷贝语义
- 3.4.5 * 移动语义
- 3.5 友元
- 3.6 运算符重载与类型转换
- 3.6.1 概述
- 3.6.2 重载方法
- 3.6.3 类型转换
- 3.7 继承与多态性
- 3.7.1 概述
- 3.7.2 派生类
- 3.7.3 子类型
- 3.7.4 虚基类
- 3.7.5 虚函数
- 3.7.6 抽象类
- 3.8 模板与泛型
- 3.8.1 概述
- 3.8.2 模板类型
- 3.8.3 *模板参数
- 3.8.4 *模板编译
- 3.8.5 *模板推断
- 3.8.6 *实例化与特例化
- 第4章 C++标准库
- 4.1 概述
- 4.2 输入输出流
- 4.2.1 概述
- 4.2.2 *流的状态
- 4.2.3 *常用流
- 4.2.4 *格式化I/O
- 4.2.5 *低级I/O
- 4.2.6 *随机访问
- 4.3 *C输入输出
- 4.3.1 *字符输入输出
- 4.3.2 *格式化输入输出
- 4.4 * 容器
- 4.4.1 * 概述
- 4.4.2 * 基本操作
- 4.4.3 * 顺序容器
- 4.4.4 * 迭代器
- 4.4.5 * 容器适配器
- 4.5 * 泛型算法
- 4.6 * 内存管理
- 4.6.1 * 自动指针
- 4.7 * 其他设施