1. 运算符重载
过一遍留个印象就行
1.3 可重载与不可重载的运算符
大多数 C++ 运算符都可以重载,但也有一些运算符是不能重载的,例如:
.(成员访问运算符).*(成员指针访问运算符)::(作用域解析运算符)sizeof(大小运算符)typeid(类型信息运算符)?:(条件运算符)#(预处理运算符)##(预处理连接运算符)
1.4 重载运算符的两种方式:成员函数和友元函数
- 成员函数重载: 运算符函数作为类的成员。左操作数隐式地绑定到
this指针。 - 友元函数重载: 运算符函数定义在类外部,但被声明为类的友元。可以访问类的私有和保护成员。通常用于需要访问两个操作数私有成员的情况,或者当左操作数不是类的对象时(例如重载流运算符)。
例子:使用成员函数重载 + 运算符
class Complex {
public:
double real;
double imag;
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
// 重载 + 运算符 (作为成员函数)
Complex operator+(const Complex& other) const {
return Complex(real + other.real, imag + other.imag);
}
};
int main() {
Complex c1(2, 3);
Complex c2(4, 5);
Complex c3 = c1 + c2; // 等价于 c1.operator+(c2);
cout << c3.real << " + " << c3.imag << "i" << endl;
return 0;
}
例子:使用友元函数重载输出流运算符 <<
#include <iostream>
class Complex {
public:
double real;
double imag;
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
friend std::ostream& operator<<(std::ostream& os, const Complex& c);
};
std::ostream& operator<<(std::ostream& os, const Complex& c) {
os << c.real << " + " << c.imag << "i";
return os;
}
int main() {
Complex c(2, 3);
std::cout << c << std::endl; // 输出:2 + 3i
return 0;
}
1.5 不同类型的运算符重载示例
- *算术运算符重载 (+, -, , /): 如上面
Complex类的例子。 - 关系运算符重载 (==, !=, <, >, <=, >=): 用于比较对象。
- 赋值运算符重载 (=): 控制对象间的赋值行为,通常需要处理深拷贝。
- *复合赋值运算符重载 (+=, -=, =, /=): 结合了运算和赋值。
- 输入/输出流运算符重载 (<<, >>): 用于自定义对象的输入和输出格式。
- 自增自减运算符重载 (++, --): 区分前缀和后缀形式需要不同的函数签名。
- 下标运算符重载 ([]): 允许像访问数组一样访问对象的元素。
- 函数调用运算符重载 (()): 使得对象可以像函数一样被调用 (函数对象或仿函数)。
1.6 运算符重载的注意事项和最佳实践
- 保持运算符的自然语义: 重载运算符的行为应该与内置类型的对应运算符保持一致。
- 不要滥用运算符重载: 只在能够提高代码可读性和直观性的情况下使用。
- 考虑返回值类型: 对于算术运算符,通常返回一个新的对象;对于赋值运算符,通常返回对象的引用 (
*this)。 - 使用
const修饰符: 对于不会修改对象状态的运算符重载,应该使用const修饰。 - 注意运算符的优先级和结合性: 重载运算符不能改变其优先级和结合性。