c++ 操作符重载详解与示例

c++ 操作符重载详解与示例

操作符重载详解

操作符重载允许为自定义类型赋予与内置类型相似的操作行为,但需遵循特定规则。以下从基本规则、实现方式、具体运算符示例及注意事项展开讲解。


一、基本规则
  1. 使用 operator 关键字

    通过定义名为 operator@ 的函数实现重载(@ 表示运算符,如 +, == 等)。

  2. 不改变运算本质

    • 不能发明新运算符(如 **)。
    • 不能改变运算符的优先级和结合性。
    • 通常不改变运算符的直观含义(如 + 应实现加法而非减法)。
  3. 参数要求

    • 参数个数与操作数相同(如 + 需两个参数)。
    • 至少一个参数为类类型(防止修改内置类型运算)。
  4. 缺省参数限制

    • operator() 外,其他运算符不能有缺省参数。

二、必须作为成员函数重载的运算符
1. 赋值运算符 =
cpp 复制代码
class MyString {
    char* data;
public:
    MyString& operator=(const MyString& other) {
        if (this != &other) {
            delete[] data;
            data = new char[strlen(other.data)+1];
            strcpy(data, other.data);
        }
        return *this;
    }
};
2. 下标运算符 []
cpp 复制代码
class Vector {
    int arr[10];
public:
    int& operator[](size_t index) { // 返回引用可修改
        return arr[index];
    }
    const int& operator[](size_t index) const {
        return arr[index];
    }
};
3. 函数调用运算符 ()
cpp 复制代码
class Adder {
public:
    int operator()(int a, int b) const {
        return a + b;
    }
};
Adder add;
int sum = add(3, 5); // 输出8
4. 成员访问运算符 ->
cpp 复制代码
class SmartPtr {
    Data* ptr;
public:
    Data* operator->() { 
        return ptr; 
    }
};
SmartPtr p;
p->func(); // 等价于(p.operator->())->func()
5. 转型运算符
cpp 复制代码
class Rational {
    int num, den;
public:
    explicit operator double() const { // 禁止隐式转换
        return static_cast<double>(num)/den;
    }
};
Rational r(3,4);
double d = static_cast<double>(r);
三、通常作为非成员函数重载的运算符
1. 算术运算符 +
cpp 复制代码
class Complex {
    double real, imag;
public:
    Complex(double r, double i) : real(r), imag(i) {}
    friend Complex operator+(const Complex& a, const Complex& b);
};

Complex operator+(const Complex& a, const Complex& b) {
    return {a.real+b.real, a.imag+b.imag};
}
2. 输入/输出运算符 << >>
cpp 复制代码
class Date {
    int y, m, d;
    friend std::ostream& operator<<(std::ostream& os, const Date& dt);
    friend std::istream& operator>>(std::istream& is, Date& dt);
};

std::ostream& operator<<(std::ostream& os, const Date& dt) {
    return os << dt.y << '-' << dt.m << '-' << dt.d;
}

std::istream& operator>>(std::istream& is, Date& dt) {
    return is >> dt.y >> dt.m >> dt.d;
}
四、特殊运算符
1. 自增/自减运算符
cpp 复制代码
class Counter {
    int value;
public:
    Counter& operator++() { // 前置++
        ++value;
        return *this;
    }
    Counter operator++(int) { // 后置++
        Counter temp = *this;
        ++value;
        return temp;
    }
};
2. 比较运算符 <=>(C++20)
cpp 复制代码
class Point {
    int x, y;
public:
    auto operator<=>(const Point&) const = default;
};
// 自动生成 ==, !=, <, <=, >, >=
五、不建议重载的运算符
1. 逻辑运算符 && ||
cpp 复制代码
// 不推荐重载,因为会失去短路特性
class BoolWrapper {
    bool value;
public:
    BoolWrapper operator&&(const BoolWrapper& other) const {
        return value && other.value;
    }
};
六、运算符重载综合示例
智能指针实现
cpp 复制代码
template<typename T>
class SmartPointer {
    T* ptr;
public:
    explicit SmartPointer(T* p = nullptr) : ptr(p) {}
    ~SmartPointer() { delete ptr; }
    
    T& operator*() const { return *ptr; }
    T* operator->() const { return ptr; }
    explicit operator bool() const { return ptr != nullptr; }
};
七、不可重载的运算符
  • 作用域解析运算符 ::
  • 成员访问运算符 .
  • 条件运算符 ?:
  • 预处理符号 # ##
最佳实践原则:
  1. 保持运算符的直观语义
  2. 对称运算符(如算术运算符)应定义为非成员函数
  3. 复合赋值运算符(如 +=)应返回左值引用
  4. 比较运算符应成对实现(C++20可用 <=> 简化)
  5. 流运算符必须定义为友元非成员函数
  6. 下标运算符应提供常量和非常量版本

示例:三维向量类

cpp 复制代码
class Vector3D {
    double x, y, z;
public:
    Vector3D operator+() const { return *this; } // 正号
    Vector3D operator-() const { return {-x, -y, -z}; } // 负号
    
    Vector3D& operator+=(const Vector3D& rhs) {
        x += rhs.x;
        y += rhs.y;
        z += rhs.z;
        return *this;
    }
    
    friend Vector3D operator+(Vector3D lhs, const Vector3D& rhs) {
        lhs += rhs;
        return lhs;
    }
    
    friend std::ostream& operator<<(std::ostream& os, const Vector3D& v) {
        return os << "(" << v.x << ", " << v.y << ", " << v.z << ")";
    }
};
相关推荐
程序猿小D18 分钟前
第27节 Node.js Buffer
linux·开发语言·vscode·node.js·c#·编辑器·vim
武昌库里写JAVA40 分钟前
【微服务】134:SpringCloud
java·开发语言·spring boot·学习·课程设计
yaoxin5211231 小时前
105. Java 继承 - 静态方法的隐藏
java·开发语言·jvm
我命由我123451 小时前
嵌入式 STM32 开发问题:烧录 STM32CubeMX 创建的 Keil 程序没有反应
c语言·开发语言·c++·stm32·单片机·嵌入式硬件·嵌入式
筏.k1 小时前
C++: 类 Class 的基础用法
android·java·c++
C++ 老炮儿的技术栈2 小时前
手动实现strcpy
c语言·开发语言·c++·算法·visual studio
一条叫做nemo的鱼2 小时前
从汇编的角度揭开C++ this指针的神秘面纱(下)
java·汇编·c++·函数调用·参数传递
Joomla中文网2 小时前
joomla5去掉后台PHP版本警告信息
开发语言·php
大磕学家ZYX2 小时前
使用Nodejs尝试小程序后端服务编写:简单的待办事项管理demo
开发语言·javascript·小程序·node.js
先做个垃圾出来………2 小时前
什么是装饰器?
开发语言·python