欢迎来到徐庆高(Tea)的个人博客网站
磨难很爱我,一度将我连根拔起。从惊慌失措到心力交瘁,我孤身一人,但并不孤独无依。依赖那些依赖我的人,信任那些信任我的人,帮助那些给予我帮助的人。如果我愿意,可以分裂成无数面镜子,让他们看见我,就像看见自己。察言观色和模仿学习是我的领域。像每个深受创伤的人那样,最终,我学会了随遇而安。
当前位置: 日志文章 > 详细内容

C++ 运算符重载的使用

2025年07月11日 C/C++
运算符重载(operator overloading)允许为自定义类型(如类、结构体)赋予类似内置类型的运算符行为,使对象之间可以使用+、-、==、<<等运算符进行操作,提升代码的可读性和

运算符重载(operator overloading)允许为自定义类型(如类、结构体)赋予类似内置类型的运算符行为,使对象之间可以使用+、-、==、<<等运算符进行操作,提升代码的可读性和易用性。

1. 基本语法

  • 通过operator关键字重载运算符。
  • 可以作为成员函数全局函数实现。

示例(成员函数):

class point {
public:
    int x, y;
    point(int x, int y) : x(x), y(y) {}
    point operator+(const point& other) const {
        return point(x + other.x, y + other.y);
    }
};

2. 加号运算符重载

成员函数方式:适用于a + b,其中a为当前对象,b为参数

class point {
public:
    int x, y;
    point(int x, int y) : x(x), y(y) {}
    // 加号运算符重载
    point operator+(const point& other) const {
        return point(x + other.x, y + other.y);
    }
};

int main() {
    point p1(1, 2), p2(3, 4);
    point p3 = p1 + p2; // 调用operator+
    std::cout << p3.x << ", " << p3.y << std::endl; // 输出4, 6
    return 0;
}

全局函数方式:适用于需要支持a + b和b + a等更灵活的场景(如左操作数不是类对象)。

class point {
public:
    int x, y;
    point(int x, int y) : x(x), y(y) {}
};

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

注意事项

  • 推荐参数为const引用,返回新对象。
  • 不建议修改参与运算的原对象(保持加法的“无副作用”)。
  • 可重载为成员函数或全局函数,具体选择视需求而定。

总结:
加号运算符重载让自定义类型支持直观的“加法”操作,提升代码可读性和易用性。

3. 左移运算符重载

左移运算符重载(operator<<)常用于自定义类型的输出,使对象可以直接用std::cout << obj的方式打印内容。通常写成全局函数,并返回ostream&支持链式输出

#include <iostream>

class point {
public:
    int x, y;
    point(int x, int y) : x(x), y(y) {}
};

// 左移运算符重载,必须为全局函数(或友元)
std::ostream& operator<<(std::ostream& os, const point& p) {
    os << "(" << p.x << ", " << p.y << ")";
    return os;
}

int main() {
    point p(3, 4);
    std::cout << p << std::endl; // 输出:(3, 4)
    return 0;
}

说明与注意事项

  • 第一个参数为std::ostream&,第二个参数为自定义类型的const引用。
  • 返回ostream&,支持链式输出(如std::cout << p1 << p2;)。
  • 通常声明为友元函数以访问私有成员:
friend std::ostream& operator<<(std::ostream&, const point&);

4. 递增运算符

递增运算符重载(operator++)允许自定义类型支持前置后置自增(如++obj和obj++)。这两种写法的重载方式略有不同。

前置递增运算符重载:

  • 语法:type& operator++();
  • 用于++obj,返回自增后的对象引用。

示例:

class counter {
    int value;
public:
    counter(int v = 0) : value(v) {}
    // 前置++
    counter& operator++() {
        ++value;
        return *this;
    }
    int get() const { return value; }
};

后置递增运算符重载:

  • 语法:type operator++(int);(int是占位参数,用于区分前置和后置)
  • 用于obj++,返回自增前的对象副本。

示例:

class counter {
    int value;
public:
    counter(int v = 0) : value(v) {}
    // 后置++
    counter operator++(int) {
        counter temp = *this;
        ++value;
        return temp;
    }
    int get() const { return value; }
};

调用:

int main() {
    counter c(5);
    ++c;            // 前置,c变为6
    c++;            // 后置,c变为7
    std::cout << c.get() << std::endl; // 输出7
    return 0;
}

注意事项

  • 前置返回引用,后置返回副本。
  • 推荐前置效率更高,后置因需保存临时副本略慢。
  • 可根据需要只重载一种或两种。

5. 赋值运算符

赋值运算符重载(operator=)允许自定义类型支持对象间的赋值操作(如a = b;)。正确实现赋值运算符对于资源管理(如动态内存)尤为重要。

基本语法:

class demo {
public:
    demo& operator=(const demo& other) {
        if (this != &other) { // 防止自赋值
            // 释放旧资源(如有)
            // 复制other的数据到当前对象
        }
        return *this; // 支持链式赋值
    }
};

典型实现:

class mystring {
    char* data;
public:
    mystring(const char* str = "") {
        data = new char[strlen(str) + 1];
        strcpy(data, str);
    }
    ~mystring() { delete[] data; }
    mystring& operator=(const mystring& other) {
        if (this != &other) {
            delete[] data; // 释放旧内存
            data = new char[strlen(other.data) + 1];
            strcpy(data, other.data);
        }
        return *this;
    }
};

注意事项:

  • 防止自赋值:if (this != &other),避免自我释放导致数据丢失。
  • 释放旧资源:先释放当前对象持有的资源,防止内存泄漏。
  • 深拷贝:如有指针成员,需分配新内存并复制内容。
  • 返回自身引用:return *this;,支持链式赋值(如a = b = c;)。

6. 关系运算符重载

关系运算符重载允许自定义类型支持比较操作(如==、!=、<、>、<=、>=),使对象之间可以像内置类型一样进行比较。

常见关系运算符重载:

  • operator==:等于
  • operator!=:不等于
  • operator< :小于
  • operator> :大于
  • operator<=:小于等于
  • operator>=:大于等于

示例

class point {
public:
    int x, y;
    point(int x, int y) : x(x), y(y) {}

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

    // 小于运算符重载(按字典序)
    bool operator<(const point& other) const {
        return (x < other.x) || (x == other.x && y < other.y);
    }
};

int main() {
    point p1(1, 2), p2(1, 2), p3(2, 3);
    std::cout << std::boolalpha;
    std::cout << (p1 == p2) << std::endl; // true
    std::cout << (p1 < p3) << std::endl;  // true
    return 0;
}

注意事项:

  • 推荐参数为const引用,成员函数加const保证不修改对象。
  • 只需重载==和<,其余可用标准库std::rel_ops自动推导(或手动实现)。
  • 关系运算符重载应符合直观语义,避免误用。

7. 函数调用运算符重载

函数调用运算符重载(operator())允许对象像函数一样被调用,这种对象称为“仿函数”或“函数对象”。

函数调用运算符重载(operator())

  • 通过重载operator(),可以让对象像函数一样使用,常用于自定义算法、回调、stl等场景。

示例:

class adder {
    int base;
public:
    adder(int b) : base(b) {}
    int operator()(int x) const {
        return base + x;
    }
};

int main() {
    adder add5(5);
    std::cout << add5(10) << std::endl; // 输出15
    return 0;
}
  • 可以有多个参数,也可以重载多次实现不同参数列表。
  • 支持捕获状态(如成员变量),比普通函数更灵活。

8. 其他运算符重载

下标运算符重载(operator[]):使对象支持数组下标访问

示例:

  class array {
      int data[10];
  public:
      int& operator[](int idx) { return data[idx]; }
  };  

箭头运算符重载(operator->):使对象像指针一样访问成员。

  class ptr {
      demo* p;
  public:
      demo* operator->() { return p; }
  };  

类型转换运算符重载(operator 类型):实现对象到其他类型的隐式或显式转换。

  class demo {
      int value;
  public:
      operator int() const { return value; }
  };  

9. 注意事项

  • 运算符重载应符合直观语义,避免滥用。
  • 某些运算符(如[]、()、->、=)必须为成员函数。
  • 运算符重载不能改变运算符的优先级和结合性。

到此这篇关于c++ 运算符重载的使用的文章就介绍到这了,更多相关c++ 运算符重载内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!