1、原理

在c++中,运算符其实就是特殊名字的函数。

普通函数:

int add(int a,int b) {return a + b;}

运算符重载:

int operator+(int a, int b) { return a + b; }

编译器看到a+b,如果a或b是类对象,就会查找是否定义了operator+来处理。

注意:运算符重载 不会改变运算符的优先级和结合性,只改变“运算时的含义”。

2、运算重载符的使用

2.1 成员函数方式

class Number {
public:
    int value;
    Number(int v) : value(v) {}
    // 成员函数重载 + (左边必须是本类对象)
    Number operator+(const Number& other) const {
        return Number(value + other.value);
    }
};

int main() {
    Number num1(10);
    Number num2(20);
    Number num3 = num1 + num2; //与num1.operator+(b)等价
    cout << num3.value << endl;
    return 0;
}

2.2 全局函数(友元)方式

class Number {
public:
    int value;
    Number(int v) : value(v) {}
    // 让友元函数能访问私有成员
    friend Number operator+(const Number& lhs, const Number& rhs);
};
// 定义全局函数
Number operator+(const Number& lhs, const Number& rhs) {
    return Number(lhs.value + rhs.value);
}
int main() {
    Number num1(10);
    Number num2(20);
    Number num3 = num1 + num2;//与num1.operator+(b)等价
    cout << num3.value << endl;
    return 0;
}

两种方式的区别:

成员函数:左操作数必须是本类对象

全局函数:更加灵活,比如int+Number也可以支持

3、常见可重载运算符

算术运算符:+ - * / %

关系运算符:== != < > <= >=

逻辑运算符:&& || !

输入输出:<< >>

下标运算符:[]

函数调用:()

自增自减:++ --

赋值运算符:=(建议总是重载)

其他:-> ->* , new delete

4、常用模板

算术运算符

class Number {
    int value;
public:
    Number(int v = 0) : value(v) {}
    // 加法
    Number operator+(const Number& other) const {
        return Number(value + other.value);
    }
    // 减法
    Number operator-(const Number& other) const {
        return Number(value - other.value);
    }
    // 乘法
    Number operator*(const Number& other) const {
        return Number(value * other.value);
    }
    // 除法(带异常处理)
    Number operator/(const Number& other) const {
        if (other.value == 0) throw runtime_error("除数不能为 0");
        return Number(value / other.value);
    }
    int get() const { return value; }
};

赋值运算符

class MyClass {
    int* data;
public:
    MyClass(int v = 0) { data = new int(v); }
    ~MyClass() { delete data; }

    // 赋值运算符重载
    MyClass& operator=(const MyClass& other) {
        if (this == &other) return *this; // 防止自赋值
        *data = *(other.data);            // 深拷贝
        return *this;
    }
};

比较运算符

class Person {
    int age;
public:
    Person(int a) : age(a) {}
    bool operator==(const Person& other) const {
        return age == other.age;
    }
    bool operator!=(const Person& other) const {
        return age != other.age;
    }
    bool operator<(const Person& other) const {
        return age < other.age;
    }
    bool operator>(const Person& other) const {
        return age > other.age;
    }
};

输出/输入运算符

class Point {
    int x, y;
public:
    Point(int x=0, int y=0): x(x), y(y) {}
    // 输出
    friend ostream& operator<<(ostream& os, const Point& p) {
        os << "(" << p.x << "," << p.y << ")";
        return os;
    }
    // 输入
    friend istream& operator>>(istream& is, Point& p) {
        is >> p.x >> p.y;
        return is;
    }
};

下标运算符

class Array {
    int data[10];
public:
    int& operator[](int index) {       // 可修改
        return data[index];
    }
    const int& operator[](int index) const { // 只读
        return data[index];
    }
};

自增自减

class Counter {
    int value;
public:
    Counter(int v=0): value(v) {}
    // 前置 ++
    Counter& operator++() {
        ++value;
        return *this;
    }
    // 后置 ++
    Counter operator++(int) {
        Counter temp = *this;
        value++;
        return temp;
    }
    int get() const { return value; }
};

函数调用运算符

class Adder {
    int base;
public:
    Adder(int b): base(b) {}
    int operator()(int x) const {  // 调用对象像函数
        return base + x;
    }
};


Adder add5(5);
cout << add5(10);  // 输出 15

指针

class SmartPtr {
    int* ptr;
public:
    SmartPtr(int* p): ptr(p) {}
    ~SmartPtr() { delete ptr; }

    int& operator*() { return *ptr; }   // *p
    int* operator->() { return ptr; }   // p->成员
};

5、一个极简的 2D 向量,用来演示运算符重载

#pragma once
#include <iostream>
// 加/减是逐分量运算;标量乘对每个分量生效;== 比较两个分量相等;<< 友好打印
struct Vec2 {
    double x{0}, y{0};
    Vec2() = default;
    Vec2(double x, double y) : x(x), y(y) {}
    // 加法:逐分量相加
    // v3 = v1 + v2  等价于:v3 = Vec2(v1.x + v2.x, v1.y + v2.y)
    Vec2 operator+(const Vec2& rhs) const {
        return Vec2{x + rhs.x, y + rhs.y};
    }
    // 减法:逐分量相减
    // v3 = v1 - v2  等价于:v3 = Vec2(v1.x - v2.x, v1.y - v2.y)
    Vec2 operator-(const Vec2& rhs) const {
        return Vec2{x - rhs.x, y - rhs.y};
    }
    // 复合赋值:+=
    // v1 += v2  等价于:v1 = v1 + v2
    Vec2& operator+=(const Vec2& rhs) {
        x += rhs.x; y += rhs.y;
        return *this;
    }
    // 一元取反:-v  (方向取反)
    // v2 = -v1  等价于:Vec2(-v1.x, -v1.y)
    Vec2 operator-() const {
        return Vec2{-x, -y};
    }
    // 与标量的乘法(右乘)
    // v2 = v1 * 2  等价于:Vec2(v1.x*2, v1.y*2)
    Vec2 operator*(double k) const {
        return Vec2{x * k, y * k};
    }
    // 比较:两个分量都相等才算相等
    bool operator==(const Vec2& rhs) const {
        return x == rhs.x && y == rhs.y;
    }
    bool operator!=(const Vec2& rhs) const { return !(*this == rhs); }
    // 友元:输出(友好打印)
    // std::cout << v  输出形如 (x,y)
    friend std::ostream& operator<<(std::ostream& os, const Vec2& v) {
        return os << "(" << v.x << "," << v.y << ")";
    }
    // —— 可选:下标访问(演示):v[0] 是 x,v[1] 是 y —— //
    double& operator[](int i) {
        return (i == 0) ? x : y; // 为简单起见不做越界检查
    }
    const double& operator[](int i) const {
        return (i == 0) ? x : y;
    }
};
// 标量在左、向量在右的乘法(左乘)
// v2 = 2 * v1  等价于:Vec2(v1.x*2, v1.y*2)
inline Vec2 operator*(double k, const Vec2& v) {
    return Vec2{v.x * k, v.y * k};
}

int main() {
    Vec2 a{3, 4};
    Vec2 b{1, -2};
    // 基本:+  -  一元-
    Vec2 s1 = a + b;   // 加:逐分量 (3+1, 4+(-2)) = (4,2)
    Vec2 s2 = a - b;   // 减:逐分量 (3-1, 4-(-2)) = (2,6)
    Vec2 neg = -a;     // 取反:(-3, -4)
    // 复合赋值:+=
    Vec2 c = a;
    c += b;            // 等价于:c = c + b
    // 标量乘:向量*标量 与 标量*向量 都支持
    Vec2 m1 = a * 2;   // (6,8)
    Vec2 m2 = 2 * a;   // (6,8)
    // 比较:==  !=
    bool eq1 = (a == Vec2{3,4}); // true
    bool eq2 = (a != b);         // true
    // 下标访问:0->x  1->y
    double ax = a[0]; // 3
    double ay = a[1]; // 4
    // 友好输出:<<
    std::cout << "a=" << a << "\n";
    std::cout << "b=" << b << "\n";
    std::cout << "a+b=" << s1 << "\n";
    std::cout << "a-b=" << s2 << "\n";
    std::cout << "-a=" << neg << "\n";
    std::cout << "c=a; c+=b -> c=" << c << "\n";
    std::cout << "a*2=" << m1 << ", 2*a=" << m2 << "\n";
    std::cout << "eq1=" << std::boolalpha << eq1
              << ", eq2=" << eq2 << "\n";
    std::cout << "a[0]=" << ax << ", a[1]=" << ay << "\n";
    // —— “语法糖背后的等价形式” —— //
    // a + b 等价于 a.operator+(b)
    Vec2 sugar1 = a + b;
    Vec2 same1  = a.operator+(b);
    // 2 * a 等价于 ::operator*(2, a)  (因为左操作数不是 Vec2)
    Vec2 sugar2 = 2 * a;
    Vec2 same2  = operator*(2, a);
    // 输出验证
    std::cout << "[sugar1=" << sugar1 << ", same1=" << same1 << "]\n";
    std::cout << "[sugar2=" << sugar2 << ", same2=" << same2 << "]\n";
    return 0;
}

更多推荐