当前位置: 首页 > news >正文

C++运算符重载全面总结

C++运算符重载全面总结

运算符重载是C++中一项强大的特性,它允许程序员为自定义类型定义运算符的行为。以下是关于C++运算符重载的详细总结:

一、基本概念

1. 什么是运算符重载

运算符重载是指为自定义类型(类或结构体)重新定义或重载已有的运算符,使其能够操作该类型的对象。

2. 运算符重载的限制

  • 不能创建新的运算符
  • 不能改变运算符的优先级和结合性
  • 不能改变运算符的操作数个数
  • 部分运算符不能被重载(如::, .*, ., ?:等)
  • 重载运算符至少有一个操作数是用户定义类型

二、运算符重载的实现方式

1. 成员函数重载

运算符作为类的成员函数重载,隐含this指针作为第一个操作数。

class Complex {
public:
    Complex operator+(const Complex& other) const {
        return Complex(real + other.real, imag + other.imag);
    }
private:
    double real, imag;
};

2. 友元函数重载

运算符作为非成员函数重载,通常需要声明为友元以访问私有成员。

class Complex {
    friend Complex operator+(const Complex& a, const Complex& b);
};

Complex operator+(const Complex& a, const Complex& b) {
    return Complex(a.real + b.real, a.imag + b.imag);
}

3. 全局函数重载

对于不访问私有成员的运算符,可以直接定义为全局函数。

Point operator+(const Point& a, const Point& b) {
    return Point(a.x() + b.x(), a.y() + b.y());
}

三、可重载运算符分类

1. 算术运算符

+, -, *, /, %, +=, -=, *=, /=, %=

class Complex {
public:
    Complex& operator+=(const Complex& other) {
        real += other.real;
        imag += other.imag;
        return *this;
    }
};

2. 关系运算符

==, !=, <, >, <=, >=

bool operator==(const Point& a, const Point& b) {
    return a.x() == b.x() && a.y() == b.y();
}

3. 逻辑运算符

!, &&, ||

class Boolean {
public:
    bool operator!() const { return !value; }
};

4. 位运算符

&, |, ^, ~, <<, >>, &=, |=, ^=, <<=, >>=

class BitMask {
public:
    BitMask operator<<(int shift) const {
        return BitMask(mask << shift);
    }
};

5. 赋值运算符

=, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=

class String {
public:
    String& operator=(const String& other) {
        // 实现深拷贝
        return *this;
    }
};

6. 递增递减运算符

++, --(前缀和后缀)

class Counter {
public:
    // 前缀++
    Counter& operator++() {
        ++count;
        return *this;
    }
    
    // 后缀++
    Counter operator++(int) {
        Counter temp = *this;
        ++count;
        return temp;
    }
};

7. 下标运算符

[]

class Array {
public:
    int& operator[](size_t index) {
        return data[index];
    }
    
    const int& operator[](size_t index) const {
        return data[index];
    }
};

8. 函数调用运算符

()

class Functor {
public:
    int operator()(int x, int y) {
        return x + y;
    }
};

9. 成员访问运算符

->, ->*

class SmartPtr {
public:
    T* operator->() const {
        return ptr;
    }
};

10. 类型转换运算符

operator type()

class Rational {
public:
    operator double() const {
        return static_cast<double>(numerator) / denominator;
    }
};

11. 内存管理运算符

new, new[], delete, delete[]

class MemoryPool {
public:
    void* operator new(size_t size) {
        return pool.allocate(size);
    }
    
    void operator delete(void* p) {
        pool.deallocate(p);
    }
};

四、特殊运算符重载注意事项

1. 输入输出运算符

<<, >> 通常应作为友元函数重载

class Complex {
    friend ostream& operator<<(ostream& os, const Complex& c);
    friend istream& operator>>(istream& is, Complex& c);
};

ostream& operator<<(ostream& os, const Complex& c) {
    return os << c.real << "+" << c.imag << "i";
}

2. 赋值运算符

  • 应返回*this的引用以支持链式赋值
  • 需要处理自赋值情况
  • 通常需要实现拷贝赋值和移动赋值
class String {
public:
    String& operator=(const String& other) {
        if (this != &other) {
            // 实现深拷贝
        }
        return *this;
    }
    
    String& operator=(String&& other) noexcept {
        // 实现移动语义
        return *this;
    }
};

3. 类型转换运算符

  • 可以声明为explicit防止隐式转换
  • 应谨慎使用以避免意外的类型转换
class SafeBool {
public:
    explicit operator bool() const { return valid; }
};

五、运算符重载的最佳实践

  1. 保持直观性:重载的运算符行为应与内置类型相似
  2. 一致性:相关运算符应一起重载(如==!=<>等)
  3. 避免过度重载:只为有意义的操作重载运算符
  4. 考虑对称性:对于二元运算符,考虑是否需要支持交换操作数的顺序
  5. 性能考虑:尽可能使用引用和移动语义提高效率
  6. 异常安全:确保运算符重载是异常安全的

六、运算符重载示例

完整示例:复数类

class Complex {
public:
    Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
    
    // 成员函数重载
    Complex operator+(const Complex& other) const {
        return Complex(real + other.real, imag + other.imag);
    }
    
    Complex& operator+=(const Complex& other) {
        real += other.real;
        imag += other.imag;
        return *this;
    }
    
    // 前缀++
    Complex& operator++() {
        ++real;
        return *this;
    }
    
    // 后缀++
    Complex operator++(int) {
        Complex temp = *this;
        ++real;
        return temp;
    }
    
    // 友元函数重载
    friend Complex operator-(const Complex& a, const Complex& b);
    friend std::ostream& operator<<(std::ostream& os, const Complex& c);
    
    // 比较运算符
    bool operator==(const Complex& other) const {
        return real == other.real && imag == other.imag;
    }
    
    bool operator!=(const Complex& other) const {
        return !(*this == other);
    }
    
private:
    double real, imag;
};

// 非成员函数实现
Complex operator-(const Complex& a, const Complex& b) {
    return Complex(a.real - b.real, a.imag - b.imag);
}

std::ostream& operator<<(std::ostream& os, const Complex& c) {
    os << c.real << (c.imag >= 0 ? "+" : "") << c.imag << "i";
    return os;
}

七、C++20新增特性

1. 三路比较运算符 <=>

C++20引入了三路比较运算符,可以简化比较运算符的实现:

class Point {
public:
    auto operator<=>(const Point&) const = default;
    // 自动生成 ==, !=, <, <=, >, >=
};

2. 重载co_await

C++20协程支持重载co_await运算符。

总结

运算符重载是C++中实现自定义类型行为一致性的重要手段。合理使用运算符重载可以使代码更直观、更易读。但同时也要注意不要滥用,确保重载的运算符行为符合直觉,并遵循语言惯例。

相关文章:

  • 【题解-Acwing】831. KMP字符串
  • 【Python爬虫】简单介绍2
  • 【美容和医美作为智商税的本质】
  • 使用 Python 实现凯撒密码的加密、解密及破译算法
  • 64. 评论日记
  • C++ Primer Plus 章节编程题练习 1-9章包含题目,答案以及知识点总结
  • 企业级RAG行业应用落地方案——阿里云百炼
  • 阿里云域名解析
  • 循环链表的基本操作及C语言代码实现
  • 高性能编程之分支预测
  • Mysql数据库基本操作-DML
  • 阿里计算机专业面试黄金宝典2
  • Hadoop大数据平台部署(Hadoop3.2.4+Hive4.0.1)
  • RabbitMQ 深度解析:从基础到高级应用的全面指南
  • 使用 Axios 进行 API 请求与接口封装
  • 傲梅分区助手单文件版:无损分区管理工具
  • 正版金币捕鱼海洋管家APP源码结构解析与运行环境说明
  • 智慧酒店企业站官网-前端静态网站模板【前端练习项目】
  • 多线性读取数据实现QCustomPlot瀑布图
  • javaSE.抛出异常
  • 夜读丨怀念那个写信的年代
  • 商务部:4月份以来的出口总体延续平稳增长态势
  • “中国游”带火“中国购”,“即买即退”让外国游客购物更丝滑
  • 一张老照片里蕴含的上海文脉
  • 媒体:每一个“被偷走的人生”,都该得到公道和正义
  • 仲裁法修订草案二审稿拟增加规定规制虚假仲裁