1178 字
6 分钟
重载操作符
2023-07-13
2025-09-03

重载操作符#

重载操作符Operator overloading是C++中一种特殊的语法,允许我们自定义一些运算符的行为,使它们能够用于自定义的数据类型。

例如,我们可以自定义一个加法运算符,使它能够直接对两个自定义类型的对象进行相加,而不需要额外的函数调用。这样可以使代码更加简洁、易读,并且提高了可重用性。

C++中可以重载的运算符包括算术运算符关系运算符逻辑运算符位运算符等等。需要注意的是,不能重载的运算符有:

作用域运算符 ::、成员访问运算符 .->、三目运算符 ?:、sizeof运算符和类型转换运算符 typeid

基本语义#

return_type operator operator_symbol (parameters) {
// 函数体
}

例如#

定义#

在类中定义一个函数 operator+,如下重载加法运算符

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

或者在类定义外重载

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

解释#

  • const Complex& other:表示右操作数(即 a + b 中的 b)的常量引用
  • const:函数末尾的const表示该函数不会修改当前对象(即左操作数 a 的值)。

主函数#

int main() {
Complex c1 {1.0, 2.0};
Complex c2 {3.0, 4.0};
Complex c3 = c1 + c2;
cout << c3.real << " " << c3.imag << endl;
return 0;
}

调用方式#

当我们写 a + b 时,编译器会将其转换为 a.operator+(b)

输出结果为:

4 6

再比如:#

我们可以定义一个结构体类型表示这两个复数在复平面内的坐标,并重载加法运算符,使得我们可以直接对两个虚数进行相加。

示例代码#

  • 定义结构体
struct Complex {
double x, y;
Complex operator+ (const Complex& other) const {
return Complex {x + other.x, y + other.y};
}
};
  • 主函数
int main() {
Complex c1 {1.0, 2.0};
Complex c2 {3.0, 4.0};
Complex c3 = c1 + c2;
cout << c3.x << " " << c3.y << endl;
return 0;
}

输出结果为:

4 6

或者#

重载<<>>移位运算符到输入输出流

struct Point {
int x;
int y;
friend std::ostream& operator << (std::ostream& os, Point const& p) {
return os << '(' << p.x << ',' << p.y << ')';
}
friend std::istream& operator >> (std::istream& is, Point& p) {
return is >> p.x >> p.y;
}
};
  • 注意:这里我们使用friend关键字将operator<<声明为友元函数,这是因为根据operater的调用方式,当我们使用 std::cout << p 时,cout是左操作数,p是右操作数,则会被调用为p.operator<<(cout),即p << cout
  • 这显然与我们实际使用的cout << p不符,将operator<<声明为友元函数后,就可以访问Point的私有成员,从而正常实现我们预期的重载
  • 实际上,想要正确调用C++ 的流操作符重载机制,就必须要一个形如 std::istream& operator>>(std::istream&, Point&) 的非成员函数或友元函数,
  • 所以上面的代码等同于:
std::ostream& operator << (std::ostream& os, Point const& p) {
return os << '(' << p.x << ',' << p.y << ')';
}
std::istream& operator >> (std::istream& is, Point& p) {
return is >> p.x >> p.y;
}
  • 主函数
int main () {
Point p {1,2};
cout << p << '\n'; // prints (1,2)
cin >> p; // 读入p.x and p.y
cout << "p: " << p << '\n';
}

当然#

于是我们便可以使用重载操作符的方法替换cmp函数

  • 定义结构体
struct Edge {
int u, v, w;
bool operator<(const Edge &other) const {
return w < other.w;
}
} e[maxn];
  • 主函数
int main() {
int n, m;
cin >> n >> m;
for (int i = 1; i <= m; i++) {
cin >> e[i].u >> e[i].v >> e[i].w;
}
sort(e + 1, e + m + 1);

很显然了, 在这里我们重载了小于号运算符,使得Edge类型的对象可以进行比较,并且满足严格弱序关系,所以可以使用sort函数Edge类型的对象进行排序,相当于另写一个cmp函数所以,下面的代码效果是一样的:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int fa[maxn];
struct Edge {
int u, v, w;
} e[maxn];
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
//-------------------------------------------------------
bool cmp(Edge x, Edge y) {
return x.w < y.w;
}
//-------------------------------------------------------
int main() {
int n, m;
cin >> n >> m;
for (int i = 1; i <= m; i++){
cin >> e[i].u >> e[i].v >> e[i].w;
}
//-------------------------------------------------------
sort(e + 1, e + m + 1, cmp);
//-------------------------------------------------------
for (int i = 1; i <= n; i++) {
fa[i] = i;
}
int ans = 0, cnt = 0;
for (int i = 1; i <= m; i++) {
int fu = find(e[i].u), fv = find(e[i].v);
if (fu != fv){
fa[fu] = fv;
ans += e[i].w;
cnt++;
}
if (cnt == n - 1){
break;
}
}
cout << ans << '\n';
return 0;
}
评论由 Giscus 提供支持

重载操作符
https://blog.erina.top/posts/重载操作符/
作者
Erina Yip
发布于
2023-07-13
许可协议
CC BY-NC-SA 4.0