1178 字
6 分钟
重载操作符
重载操作符
重载操作符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;}