重载运算符---(超详细的保姆级教程)

一. 简单介绍什么是重载运算符

1.重载运算符的定义

运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。-- 百度
将系统预定义的运算符,用于用户自定义的数据类型,这就是运算符重载。运算符重载的实质就是函数重载 – b站

通俗一点来说,就是编译软件本身的运算符不符合我们想要的运算符定义,我们需要重新定义运算符来达到我们的目的。 比如我们定义一个名为xlx77的结构体,当我们想直接输出一个结构体的时候是不被允许的,我们就可以重新定义 << ,来达到我们的目的

2. 重载运算符的基本格式

重载运算符的一般格式为:
返回类型 operator@(参数表)
{
重载函数体;
}

3. 可以重载的运算符和不能重载的运算符

请添加图片描述
请添加图片描述

4. 重载运算符的规则

1. 不允许定义新的运算符
2. 不能改变该运算符操作数(对象)的个数
3. 不能改变该运算符的优先级别和结合性
4. 应该符合实际需要,重载的功能应该与运算符原有的功能相似,避免没有目的的使用重载运算符

5.重载运算符函数的分类

  1. 成员运算符函数
  2. 友元运算符函数
    运算符重载为友元函数,在相应的类中声明为该类的友元函数,声明的一般形式为:
    friend 返回类型 operator@(参数表){函数体}

二. 几种常见运算符的重载

总代码:

我定义了一个名为xlx77的结构体,内有两个double元素a和b,重载了 + ,前置++,后置++, = , << , >> 等运算符。

#include<iostream>
using namespace std ;
class xlx77
{
public:
    double a , b ;
    void show()
    {
        cout << a << b << endl;
    }
    xlx77 operator+(xlx77 & c2){
        xlx77 temp;
        temp.a = this ->a + c2.a;
        temp.b = this ->b + c2.b;
        return temp;
    }
    xlx77 operator++(){ //前置
        this ->a ++;
        this ->b ++;
        return *this;
    }
    xlx77 operator++(int){ //后置
        xlx77 temp = *this;
        this ->a ++;
        this ->b ++;
        return temp;
    }
    xlx77 operator=(const xlx77 & c){
        this ->a = c.a;
        this ->b = c.b;
        return *this;
    }
    friend ostream & operator <<(ostream& myout,const xlx77& c1);
    friend istream & operator <<(istream& myin,const xlx77& c1);
};
ostream & operator<<(ostream&myout,xlx77& c1){
    cout <<" a is " << c1.a << "b is " << c1.b << endl ;
    return myout ;
}
istream & operator>>(istream& myin,xlx77& c1){
    cin >> c1.a >> c1.b  ;
    return myin;
}
int main()
{
    xlx77 x1,x2;
    cin >> x1 >> x2 ;
    cout << x1 << x2 ;
    xlx77 c3 = x1 + x2 ;
    cout << c3 ;
    xlx77 c4 = ++c3;
    //xlx77 c4 = c1.operator++();
    cout << c4 ;
    xlx77 c5 = c4++;
    cout << c5 ;
    c5 = x2 = x1 ;
    cout << x2  << c5;
    return 0 ;
}

1.输入输出运算符 >> 和 <<

标准输入流对象cin,是istream类的对象,用于处理标准输入(即键盘输入)
标准输出流对象cout,是ostream类的对象,用于处理标准输出(即屏幕输出)
只能采用友元函数的形式,通常格式如下:
ostream & operator<<(ostream & , const 类对象引用);
istream & operator >> (istream & , 类对象引用);

ostream & operator<<(ostream&myout,xlx77& c1){
    cout <<" a is " << c1.a << "b is " << c1.b << endl ;
    return myout ;
}
istream & operator>>(istream& myin,xlx77& c1){
    cin >> c1.a >> c1.b  ;
    return myin;
}

这两个是在结构体之外的函数,要在结构体内声明这个函数是结构体的友元函数

friend ostream & operator <<(ostream& myout,const xlx77& c1);
    friend istream & operator <<(istream& myin,const xlx77& c1);

这个重载运算符的目的是想直接像输入输出一个普通数据类型的数一样的输入输出,如果不重定义运算符的话,也可以输入输出,可以来一个对比。
重定义前:

xlx77 x1;
cin >> x1.a >> x1.b;

重定义后:

xlx77 x1;
cin >> x1;

2. 自增运算符 ++

xlx77 operator++(){ //前置
        this ->a ++;
        this ->b ++;
        return *this;
    }
    xlx77 operator++(int){ //后置
        xlx77 temp = *this;
        this ->a ++;
        this ->b ++;
        return temp;
    }

自增运算符,分两种情况,分别是前置和后置,就是++a或者a++
当为前置的时候,先加后返回

当为后置的时候,先赋值后加,所以后置的时候,定义了一个临时结构体temp,返回了temp,此时的temp并没有++也就是自增

3. 赋值运算符 =

1 赋值运算符“=”是双目运算符
2 如果不定义自己的赋值运算符函数,那么编译器会自动生成一个默认的赋值运算符函数
3 赋值运算符函数必须是类的成员函数,不允许重载为友元函数
4 赋值运算符函数不能被派生类继承

xlx77 operator=(const xlx77 & c){
        this ->a = c.a;
        this ->b = c.b;
        return *this;
    }

如果是重载双目运算符,就只要设置一个参数作为右侧运算量,而左侧运算量就是该对象本身 :这就是为什么=双目运算符,参数只设置了一个作为右侧运算量
如果是重载单目运算符,就不必另外设置参数,运算符的操作量就是对象本身
双目运算符是指运算所需变量为两个的运算符,或者要求运算对象的个数是2的运算符称为双目运算符;运算所需变量为一个的运算符叫单目运算符,例如【!,~,()】;运算所需变量为三个的运算符叫三目运算符:【?:】

4. 加法运算符+

xlx77 c3 = c1.operator + (c2) ; 显式调用
operator+是结构体内返回值为结构体的函数,所以结构体中operator+的this就是c1的指针,返回的是结构体 temp;

xlx77 operator+(xlx77 & c2){
        xlx77 temp;
        temp.a = this ->a + c2.a;
        temp.b = this ->b + c2.b;
        return temp;
    }

但是一般我们都是用隐式调用,就跟平常的加减法一样的格式。
xlx77 c3 = c1 + c2 ; 隐式调用

三. 例题:结构体运算符重载

1.例题

Kruskal算法求最小生成树
https://www.acwing.com/problem/content/861/
题目的大概意思就是给你一个无向图,可能有重边和自环,如果能找到这个图的最小生成树就输出最小生成树的权重之和,否则输出 impossibe – acwing

2. 分析与解决

这里我定义一个结构体,把所有的边的权值存进去来进行排序,想让它从小到大遍历每一条边,如果边的两个点不在一个并查集内,就把两个点加在一个并查集内。总共有n个点,所以最后如果存够了n-1条边,那么就存在最小生成树。
但是sort不能直接对结构体进行排序,所以要重构运算符,让左侧元素的w权重小于右侧w权重为true,让程序认为sort的排序规则是从小到大

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10,M=2*N;
int n,m;
// 并查集 
int p[N];
struct Edge{
	int a,b,w;
	// 重载小于运算符 
	bool operator< (const Edge &W) {
		return this->w<W.w;
	}
}edges[M];
int find(int x) {
	if(p[x]!=x) p[x]=find(p[x]);
	return p[x];
}
int main() {
	cin>>n>>m;
	for(int i=0;i<m;i++) {
		int a,b,w;	cin>>a>>b>>w;
		edges[i]={a,b,w};
	}
	sort(edges,edges+m);
	
	// 初始化并查集
	for(int i=1;i<=n;i++) p[i]=i;
	// 从小到大枚举所有边 
	int res=0,cnt=0;
	for(int i=0;i<m;i++) {
		int a=edges[i].a,b=edges[i].b,w=edges[i].w;
		a=find(a),b=find(b);
		if(a!=b) {
			p[a]=b;
			res += w;
			cnt++;
		}
	}
	
	if(cnt!=n-1) puts("impossible");
	else cout<<res<<endl; 
	return 0;
}

最后,希望这篇文章能够帮助大家的话可以点点赞支持一下,如果有什么疑问的话,评论区或者私信都可以的
请添加图片描述

  • 65
    点赞
  • 148
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三粒小金子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值