C++——运算符重载

100 阅读3分钟

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 修饰。
  • 注意运算符的优先级和结合性: 重载运算符不能改变其优先级和结合性。