C++ 重载运算符和重载函数(实战总结)

C++ 重载运算符和重载函数:让代码更自然、更优雅

在学习 C++ 的过程中,你可能会遇到这样一种情况:当你想对自定义的类对象使用 +==<< 这样的操作符时,编译器却报错说“没有匹配的运算符”。这并不是你的代码写错了,而是因为这些运算符默认只对内置类型(如 int、double)有效。而当我们希望让自定义类型也能像基本类型一样使用这些运算符时,就需要用到 C++ 的一个重要特性——重载运算符和重载函数

这就像你家的智能门锁,原本只能用钥匙开,但你可以把它设置成支持指纹、密码、手机蓝牙等多种方式。C++ 的“重载”机制,就是让你为自定义类型“定制”这些操作的方式。


什么是函数重载?

函数重载是 C++ 中最基础、最常用的多态机制之一。它允许我们使用同一个函数名,但参数列表不同,来定义多个函数。

函数重载的规则

  • 函数名必须相同。
  • 参数个数、类型或顺序必须不同。
  • 返回类型可以不同,但仅靠返回类型不同不能构成重载。

示例:加法函数的重载

// 两个整数相加
int add(int a, int b) {
    return a + b;
}

// 两个浮点数相加
double add(double a, double b) {
    return a + b;
}

// 三个整数相加
int add(int a, int b, int c) {
    return a + b + c;
}

✅ 注释说明:

  • add(int, int) 用于整数加法,返回 int 类型。
  • add(double, double) 用于浮点数加法,返回 double 类型。
  • add(int, int, int) 是三参数版本,满足函数重载的参数个数不同要求。
    编译器会根据调用时传入的参数自动选择最匹配的版本。

实际调用示例

#include <iostream>
using namespace std;

int main() {
    cout << add(3, 4) << endl;        // 输出 7,调用 int add(int, int)
    cout << add(3.14, 2.86) << endl;  // 输出 6.0,调用 double add(double, double)
    cout << add(1, 2, 3) << endl;     // 输出 6,调用 int add(int, int, int)

    return 0;
}

💡 小贴士:函数重载的本质是“编译期多态”,编译器根据参数类型在编译时决定调用哪个函数,性能高且无运行时开销。


什么是运算符重载?

运算符重载让你可以为自定义类型(如类)定义自己的运算符行为。比如,你可以让两个 Complex(复数)对象直接用 + 相加,就像两个整数一样。

语法结构

返回类型 operator 运算符 (参数列表) {
    // 实现逻辑
}

✅ 重要规则:

  • 不能改变运算符的优先级和结合性。
  • 不能重载 .::sizeof?: 这些运算符。
  • newdelete 可以重载,但通常不推荐。

重载加法运算符 +:实现复数相加

我们以复数类为例,展示如何重载 + 运算符。

#include <iostream>
using namespace std;

class Complex {
private:
    double real;   // 实部
    double imag;   // 虚部

public:
    // 构造函数
    Complex(double r = 0, double i = 0) : real(r), imag(i) {}

    // 重载加法运算符 +,返回一个新的 Complex 对象
    Complex operator+(const Complex& other) const {
        // 将两个复数的实部和虚部分别相加
        return Complex(real + other.real, imag + other.imag);
    }

    // 输出复数,格式为 a + bi
    void display() const {
        cout << real << " + " << imag << "i" << endl;
    }
};

int main() {
    Complex c1(3, 4);   // 3 + 4i
    Complex c2(1, -2);  // 1 - 2i

    // 使用重载的 + 运算符,直接相加
    Complex c3 = c1 + c2;

    cout << "c1 = ";
    c1.display();

    cout << "c2 = ";
    c2.display();

    cout << "c1 + c2 = ";
    c3.display();

    return 0;
}

✅ 注释说明:

  • operator+ 是一个成员函数,接收另一个 Complex 对象的引用(避免拷贝)。
  • const 修饰表示该函数不会修改当前对象的状态,是“只读”操作。
  • 返回值是一个新的 Complex 对象,即相加结果。
  • 调用 c1 + c2 实际上等价于 c1.operator+(c2)

重载输出运算符 <<:让自定义类型也能用 cout

C++ 默认不支持 cout << Complex 这种写法。但通过重载 <<,我们可以让它变得像输出整数一样自然。

重载 << 运算符

// 全局函数重载 << 运算符
ostream& operator<<(ostream& os, const Complex& c) {
    os << c.real << " + " << c.imag << "i";
    return os;
}

✅ 注释说明:

  • 必须是全局函数,因为 coutostream 类型,不能作为成员函数。
  • 第一个参数是 ostream&,表示输出流,必须引用传递以提高效率。
  • 第二个参数是 const Complex&,表示要输出的对象。
  • 返回 ostream& 是为了支持链式输出,如 cout << c1 << c2;

使用示例

int main() {
    Complex c1(3, 4);
    Complex c2(1, -2);

    // 现在可以直接用 cout 输出 Complex 对象
    cout << "c1 = " << c1 << endl;
    cout << "c2 = " << c2 << endl;
    cout << "c1 + c2 = " << (c1 + c2) << endl;

    return 0;
}

✅ 输出结果:

c1 = 3 + 4i
c2 = 1 + -2i
c1 + c2 = 4 + 2i

重载关系运算符 ==!=:比较两个对象

在很多场景中,我们需要判断两个对象是否相等。比如判断两个 Point(点)是否重合。

class Point {
private:
    int x, y;

public:
    Point(int x = 0, int y = 0) : x(x), y(y) {}

    // 重载 == 运算符
    bool operator==(const Point& other) const {
        return x == other.x && y == other.y;
    }

    // 重载 != 运算符(可选,但建议配合使用)
    bool operator!=(const Point& other) const {
        return !(*this == other);
    }

    void display() const {
        cout << "(" << x << ", " << y << ")" << endl;
    }
};

✅ 注释说明:

  • == 比较两个点的 x 和 y 坐标是否完全相同。
  • != 可以基于 == 实现,避免重复逻辑。
  • const 保证比较过程不修改对象。

使用示例

int main() {
    Point p1(1, 2);
    Point p2(1, 2);
    Point p3(3, 4);

    cout << "p1 = ";
    p1.display();
    cout << "p2 = ";
    p2.display();
    cout << "p3 = ";
    p3.display();

    cout << "p1 == p2: " << (p1 == p2) << endl;  // 输出 1(true)
    cout << "p1 == p3: " << (p1 == p3) << endl;  // 输出 0(false)

    return 0;
}

重载输入运算符 >>:支持 cin 输入

<< 类似,>> 也可以重载,让 cin >> point 成为可能。

istream& operator>>(istream& is, Point& p) {
    is >> p.x >> p.y;
    return is;
}

✅ 注释说明:

  • 第一个参数是输入流引用,第二个是待赋值的 Point 对象引用。
  • 返回 istream& 支持链式输入,如 cin >> p1 >> p2;

使用示例

int main() {
    Point p;
    cout << "请输入点的坐标 (x y): ";
    cin >> p;
    cout << "你输入的点是: ";
    p.display();
    return 0;
}

总结与最佳实践

C++ 重载运算符和重载函数,是让代码更自然、更符合直觉的关键机制。它们让你的类对象可以像内置类型一样使用 +<<== 等运算符,极大提升了代码的可读性和表达力。

重要建议:

  • 重载应符合语义:比如 + 应该是“相加”,而不是“拼接”。
  • 尽量使用 const 成员函数:如果函数不修改对象,加上 const
  • 返回值要合理:通常返回对象或引用,避免不必要的拷贝。
  • 输入输出运算符必须为全局函数,且返回流引用。

实际意义

当你在项目中定义一个 Matrix(矩阵)、String(字符串)或 Vector(向量)类时,重载运算符能让这些类的使用方式接近数学表达式或标准库风格,让代码更清晰、更专业。

C++ 重载运算符和重载函数,不是“炫技”,而是“让代码更像自然语言”的重要工具。掌握它,你就离写出“优雅的 C++”又近了一步。