输入关键词开始搜索

C++ 运算符重载

可重载 vs 不可重载

可重载:
  算术: + - * / % += -= *= /= %=
  比较: < > <= >= == !=
  位:   & | ^ ~ << >> &= |= ^= <<= >>=
  逻辑: ! && ||
  赋值: =
  下标: []
  调用: ()
  解引用: * ->
  自增: ++ --
  new / delete

不可重载:
  ::  .  .*  ?:  sizeof  typeid

基本原则

// ① 成员 vs 非成员
class Vec2 {
    double x, y;
public:
    // 成员函数:第一个操作数必须是本类
    Vec2 operator+(const Vec2 &other) const {
        return {x + other.x, y + other.y};
    }
    // 好处:可访问私有成员

    // 非成员(推荐对称运算符):
    friend Vec2 operator*(double s, const Vec2 &v) {
        return {s * v.x, s * v.y};
    }
    // 好处:3.0 * v 可以(左操作数隐式转换)
};

// ② 返回 const 引用的规则
// = += -=  → 返回 *this 的引用(支持链式 a=b=c)
// + - * /  → 返回新对象(值语义)
// < > ==   → 返回 bool

// ③ 不要重载逻辑运算符的短路行为
// operator&& — 两个操作数都会求值!已失去短路语义
// 基本不重载 &&

算术运算符

class Complex {
    double re, im;
public:
    // 复合赋值(成员,返回引用)
    Complex &operator+=(const Complex &rhs) {
        re += rhs.re; im += rhs.im;
        return *this;
    }

    // 二元 +(非成员,用 += 实现)
    friend Complex operator+(Complex lhs, const Complex &rhs) {
        lhs += rhs;          // 拷贝 lhs,然后 +=
        return lhs;          // 利用 RVO
    }
    // 技巧:operator+ 不访问私有成员 → 只需 operator+=
};

比较运算符(C++20 简化)

// C++17 之前 — 写 4-6 个
class Person {
    string name; int age;
public:
    bool operator==(const Person &o) const { return name == o.name && age == o.age; }
    bool operator!=(const Person &o) const { return !(*this == o); }
    bool operator< (const Person &o) const { return tie(name, age) < tie(o.name, o.age); }
};

// C++20 — 只需 <=>
class Person20 {
    string name; int age;
public:
    auto operator<=>(const Person20 &) const = default;  // 一行生成全部 6 个!
};

下标与函数调用

// 下标 operator[]
class Array {
    int *data; size_t n;
public:
    int &operator[](size_t i)       { return data[i]; }        // 可写
    int  operator[](size_t i) const { return data[i]; }        // 只读版
};

// 函数调用 operator()  → 仿函数
class Multiplier {
    int factor;
public:
    Multiplier(int f) : factor(f) {}
    int operator()(int x) const { return x * factor; }
};
Multiplier times3(3);
int nine = times3(3);  // 像函数一样调用

// 结合 std::function / 算法
vector<int> v = {1, 2, 3};
transform(v.begin(), v.end(), v.begin(), Multiplier(10));

类型转换运算符

class Wrapper {
    int value;
public:
    // 隐式转换(方便但危险)
    operator int() const { return value; }       // Wrapper → int

    // C++11 explicit — 必须显式转换
    explicit operator bool() const { return value != 0; }
};

Wrapper w{42};
int i = w;              // ✅ 隐式
// bool b = w;           // ❌ explicit
bool b = bool(w);        // ✅ 显式
if (w) { /* ... */ }     // ✅ 条件上下文允许 explicit bool

增量运算符

class Iterator {
    int pos;
public:
    Iterator &operator++()    { ++pos; return *this; }  // 前置 ++it
    Iterator  operator++(int) { auto tmp = *this; ++pos; return tmp; } // 后置 it++
    //                          ↑ 哑元 int 区分前后置
};

输出运算符

class Point {
    double x, y;
    friend ostream &operator<<(ostream &os, const Point &p) {
        return os << "(" << p.x << ", " << p.y << ")";
    }
};
// 必须是非成员:第一个参数是 ostream,不能是本类

经验法则

1. = [] () ->    → 成员函数(别无选择)
2. += -= *= /=   → 成员函数
3. + - * /       → 非成员(用 += 实现)
4. == < >        → 非成员(对称性)
5. << >>          → 非成员(第一个参数是 stream)
6. 不要重载 && || ,(破坏短路/求值顺序)