C++ 运算符重载详解:从入门到理解

C++ 运算符重载是面向对象编程的核心知识点,也是面试、考试的高频考点,更是新手最容易混淆的模块。很多同学学到这里都会被哪些运算符不能重载、哪些只能写成员函数、重载规则、返回值 / 引用区别绕晕。


一、不能重载的 5 个运算符

C++ 语法硬性规定,以下运算符不允许重载

运算符名称禁止原因
.成员访问运算符语言基础语法,不可修改
.*成员指针访问运算符用于访问类成员指针,语法固定
::作用域限定符用于区分命名空间 / 类作用域,语法固定
?:三目条件运算符语法结构特殊,无法重载
sizeof求类型大小运算符编译期计算,非运行期运算符

二、只能作为类成员函数重载的 4 个运算符

这 4 个运算符不允许写成全局函数,必须定义在类内部:

运算符名称必须成员重载原因
=赋值运算符编译器会默认生成,必须成员函数
[]下标运算符依赖对象本身,必须绑定实例
()函数调用运算符让对象可像函数一样调用,必须成员
->指针成员访问运算符智能指针核心运算符,必须成员

三、运算符重载的 6 大核心规则(必背)

这是编译器强制遵守的语法规则,违反直接报错:

1. 操作数必须包含自定义类型

重载的运算符,至少有一个操作数是 类 / 结构体 / 枚举类型

错误:不能重载两个内置类型的运算符

// 报错!两个int都是内置类型,无法修改原有规则
int operator+(int a, int b) { return a+b; }

✅ 正确:必须包含自定义类类型

class Complex{/*...*/};
Complex operator+(Complex c1, Complex c2); // 合法

2. 不能改变运算符优先级

例如 * 优先级高于 +,重载后依然不变,无法修改。

3. 不能改变运算符结合性

例如 a+b+c 依然从左到右计算,无法修改。

4. 不能改变操作数个数

双目运算符(+、-、*)重载后还是双目;单目运算符(++、--、!)重载后还是单目。

5. 不能自创运算符

只能重载 C++ 原生运算符,不能自己造 $、#、@ 等新符号。

6. 语义必须符合直觉

重载运算符要遵循原有含义:+ 表示相加、== 表示判等、[] 表示下标访问,不要乱写语义!


四、关键概念:成员函数 VS 全局函数 参数区别

这是最容易错的点,核心原因:成员函数自带隐藏的 this 指针

1. 成员函数重载(类内)

  • 双目运算符:只需要 1 个显式参数(左操作数是 this)
  • 单目运算符:0 个显式参数
// 成员函数:a + b  →  a.operator+(b)
Complex operator+(const Complex& other) const;

2. 全局函数重载(类外)

  • 双目运算符:需要 2 个参数
  • 单目运算符:需要 1 个参数
// 全局函数:a + b  →  operator+(a,b)
Complex operator+(const Complex& c1, const Complex& c2);

五、运算符返回引用 VS 返回值

C++ 没有强制规定,但工程开发有统一约定

1. 必须 / 通常返回 引用 的运算符

适用场景:返回对象本身、支持连续操作、支持赋值修改

运算符示例返回值类型
赋值 =a = b = c类&
下标 [] 非 constarr[0] = 10元素类型&
前置自增 / 自减 ++a --a++a类&
流运算符 << >>cout<<a<<bostream&/istream&

核心原因:返回引用才能实现连续调用、修改原对象


2. 必须 / 通常返回 的运算符

适用场景:产生新对象、不修改原操作数、返回临时结果

运算符示例返回值类型
算术运算符 + - * / %a + b新对象
后置自增 / 自减 a++ a--a++旧值副本
比较运算符 == != < >a == bbool
逻辑运算符 `! &&`!abool

核心原因:运算结果是临时新值,和原对象无关,必须返回值!


六、完整实战代码

#include <iostream>
using namespace std;

// 复数类:演示运算符重载
class Complex {
public:
    Complex(double real = 0, double imag = 0) : _real(real), _imag(imag) {}

    // 1. 赋值运算符 = :返回引用(成员函数)
    Complex& operator=(const Complex& other) {
        if (this != &other) {
            _real = other._real;
            _imag = other._imag;
        }
        return *this;
    }

    // 2. 加法运算符 + :返回值(成员函数)
    Complex operator+(const Complex& other) const {
        return Complex(_real + other._real, _imag + other._imag);
    }

    // 3. 前置++ :返回引用
    Complex& operator++() {
        _real++;
        _imag++;
        return *this;
    }

    // 4. 后置++ :返回值
    Complex operator++(int) {
        Complex temp = *this;
        _real++;
        _imag++;
        return temp;
    }

    // 5. 下标运算符 [] :返回引用
    double& operator[](int index) {
        if (index == 0) return _real;
        else return _imag;
    }

    // 6. 比较运算符 == :返回bool
    bool operator==(const Complex& other) const {
        return _real == other._real && _imag == other._imag;
    }

    // 友元声明:流运算符
    friend ostream& operator<<(ostream& out, const Complex& c);
    friend istream& operator>>(istream& in, Complex& c);

private:
    double _real;
    double _imag;
};

// 流输出 << :返回引用(全局函数)
ostream& operator<<(ostream& out, const Complex& c) {
    out << c._real << " + " << c._imag << "i";
    return out;
}

// 流输入 >> :返回引用(全局函数)
istream& operator>>(istream& in, Complex& c) {
    in >> c._real >> c._imag;
    return in;
}

// 测试
int main() {
    Complex c1(1, 2), c2(3, 4);
    Complex c3 = c1 + c2;
    cout << "c1 + c2 = " << c3 << endl;

    ++c1;
    cout << "前置++ c1: " << c1 << endl;

    c2++;
    cout << "后置++ c2: " << c2 << endl;

    cout << "c1[0] = " << c1[0] << endl;
    c1[0] = 10;
    cout << "修改后c1: " << c1 << endl;

    return 0;
}

七、速记表

1. 不能重载

. .* :: ?: sizeof

2. 只能成员重载

= [] () ->

3. 重载核心规则

至少一个自定义类型 + 不改变优先级 / 结合性 / 参数个数

4. 返回引用

= [] 前置++/-- << >>

5. 返回值

+ - * / % 后置++/-- == != < > !


总结

运算符重载的核心就两点:

  1. 遵守语法规则:记住不能重载、只能成员重载的运算符;
  2. 遵循语义规范:修改自身 / 连续操作返回引用,产生新结果返回值。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值