文章目录

C++ 运算符重载:+、-、*、/ 操作符

发布于 2026-04-19 01:17:08 · 浏览 5 次 · 评论 0 条

C++ 运算符重载:+、-、*、/ 操作符

运算符重载是 C++ 中的一项强大功能,它允许你赋予自定义对象(如类或结构体)使用标准运算符(如 +-*/)的能力。这使得代码更符合直觉,读起来更像自然语言。

本文将以“复数”运算为例,手把手教你如何实现这四个基本算术运算符的重载。


1. 准备基础类结构

首先,我们需要定义一个表示复数的类 Complex。复数包含实部和虚部。

定义 一个名为 Complex 的类,包含两个私有成员变量 real(实部)和 imag(虚部),以及一个公共构造函数用于初始化这两个值。

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

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

    // 用于打印结果的辅助函数
    void display() const {
        cout << "(" << real << ", " << imag << "i)" << endl;
    }

    // 声明友元函数,以便后续重载 << 运算符(可选)
    friend ostream& operator<<(ostream& os, const Complex& c);
};

2. 重载加法运算符 (+)

加法运算符的目的是将两个复数对象相加。我们需要返回一个新的 Complex 对象,该对象包含两个操作数实部与虚部的和。

编写 成员函数 operator+,它接受一个 Complex 类型的常量引用作为参数。

实现 逻辑:将当前对象的实部与参数对象的实部相加,虚部同理,然后返回 这个新的临时对象。

$$ (a + bi) + (c + di) = (a+c) + (b+d)i $$

// 在类定义内部添加
Complex operator+(const Complex& other) const {
    // 返回一个新的 Complex 对象
    return Complex(this->real + other.real, this->imag + other.imag);
}

3. 重载减法运算符 (-)

减法与加法非常相似,只是将运算逻辑从相加改为相减。

编写 成员函数 operator-,同样接受一个 Complex 类型的常量引用。

实现 逻辑:用当前对象的实部减去参数对象的实部,虚部同理。

$$ (a + bi) - (c + di) = (a-c) + (b-d)i $$

// 在类定义内部添加
Complex operator-(const Complex& other) const {
    return Complex(this->real - other.real, this->imag - other.imag);
}

4. 重载乘法运算符 (*)

复数乘法比加减法稍复杂,需要应用分配律和虚数单位 $i^2 = -1$ 的性质。

编写 成员函数 operator*

实现 逻辑:

  1. 计算实部:real * other.real - imag * other.imag(因为 $i \times i = -1$,这里要减去)。
  2. 计算虚部:real * other.imag + imag * other.real

$$ (a + bi) \times (c + di) = (ac - bd) + (ad + bc)i $$

// 在类定义内部添加
Complex operator*(const Complex& other) const {
    double r = this->real * other.real - this->imag * other.imag;
    double i = this->real * other.imag + this->imag * other.real;
    return Complex(r, i);
}

5. 重载除法运算符 (/)

复数除法通常通过有理化分母来实现,即将分母中的虚数消除。

编写 成员函数 operator/

实现 逻辑:

  1. 首先计算分母:$c^2 + d^2$。
  2. 检查 分母是否为 0,避免除以零错误。
  3. 计算实部:$(ac + bd) / (c^2 + d^2)$。
  4. 计算虚部:$(bc - ad) / (c^2 + d^2)$。

$$ \frac{a + bi}{c + di} = \frac{(ac + bd) + (bc - ad)i}{c^2 + d^2} $$

// 在类定义内部添加
Complex operator/(const Complex& other) const {
    double denominator = other.real * other.real + other.imag * other.imag;
    if (denominator == 0) {
        throw runtime_error("Division by zero"); // 简单的错误处理
    }
    double r = (this->real * other.real + this->imag * other.imag) / denominator;
    double i = (this->imag * other.real - this->real * other.imag) / denominator;
    return Complex(r, i);
}

6. 完整代码与测试

将上述所有部分组合起来,并在 main 函数中进行测试。

复制 以下完整代码到你的 C++ 开发环境中。

编译运行 程序,观察输出结果。

#include <iostream>
#include <stdexcept>
using namespace std;

class Complex {
private:
    double real;
    double imag;

public:
    Complex(double r = 0, double i = 0) : real(r), imag(i) {}

    // 重载 +
    Complex operator+(const Complex& other) const {
        return Complex(this->real + other.real, this->imag + other.imag);
    }

    // 重载 -
    Complex operator-(const Complex& other) const {
        return Complex(this->real - other.real, this->imag - other.imag);
    }

    // 重载 *
    Complex operator*(const Complex& other) const {
        double r = this->real * other.real - this->imag * other.imag;
        double i = this->real * other.imag + this->imag * other.real;
        return Complex(r, i);
    }

    // 重载 /
    Complex operator/(const Complex& other) const {
        double denominator = other.real * other.real + other.imag * other.imag;
        if (denominator == 0) {
            throw runtime_error("Division by zero");
        }
        double r = (this->real * other.real + this->imag * other.imag) / denominator;
        double i = (this->imag * other.real - this->real * other.imag) / denominator;
        return Complex(r, i);
    }

    // 重载输出运算符 << 以便直接打印对象
    friend ostream& operator<<(ostream& os, const Complex& c) {
        os << "(" << c.real << ", " << c.imag << "i)";
        return os;
    }
};

int main() {
    Complex c1(4.0, 3.0); // 4 + 3i
    Complex c2(2.0, 1.0); // 2 + 1i

    Complex sum = c1 + c2;
    Complex diff = c1 - c2;
    Complex prod = c1 * c2;
    Complex quot = c1 / c2;

    cout << "c1: " << c1 << endl;
    cout << "c2: " << c2 << endl;
    cout << "c1 + c2 = " << sum << endl;
    cout << "c1 - c2 = " << diff << endl;
    cout << "c1 * c2 = " << prod << endl;
    cout << "c1 / c2 = " << quot << endl;

    return 0;
}

7. 运算符重载机制解析

当编译器遇到 c1 + c2 时,它会将其转换为函数调用。下图展示了 c1 + c2 的执行流程。

graph LR A["对象 c1 (4+3i)"] -- "调用 c1.operator+" --> B("执行函数体\n计算 real+real, imag+imag") C["对象 c2 (2+1i)"] -. "作为参数 other 传入" .-> B B -- "返回临时对象" --> D["结果 (6+4i)"]

8. 成员函数 vs 非成员函数选择指南

在上面的例子中,我们将运算符重载为成员函数。但在某些情况下,推荐使用非成员函数(友元函数)。以下是两者的对比,帮助你做决定。

特性 成员函数 非成员函数
参数数量 二元运算符只需 1 个参数(隐含 this 指针) 二元运算符需要 2 个参数
左侧操作数 必须是当前类的对象 可以是兼容类型(如 int + Complex
对称性 不对称(c1 + 5 可以,5 + c1 不行) 对称(5 + c1c1 + 5 都可以)
访问权限 直接访问私有成员 需要通过 friend 声明访问私有成员

决策建议

  • 如果运算符修改左操作数(如 =+=),使用成员函数。
  • 如果运算符不修改操作数且需要类型转换对称性(如 +-*/),优先使用非成员函数(友元)。

operator+ 改写为非成员函数的示例:

// 在类外部定义
class Complex {
    // ... 其他成员 ...
    friend Complex operator+(const Complex& c1, const Complex& c2);
};

// 非成员函数实现
Complex operator+(const Complex& c1, const Complex& c2) {
    return Complex(c1.real + c2.real, c1.imag + c2.imag);
}

注意:对于复数这种纯数学对象,使用成员函数或非成员函数都是可接受的,只要保持一致性即可。但对于涉及不同类型混合运算的场景(如 Complex + int),非成员函数会更灵活。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文