第五层:C++中的运算符重载

🎉welcome🎉
✒️博主介绍一名大一的智能制造专业学生在学习C/C++的路上会越走越远后面不定期更新有关C/C++语法数据结构算法Linuxue5使用制作游戏的心得和大家一起共同成长。
✈️C++专栏C++爬塔日记
😘博客制作不易👍点赞+⭐收藏+➕关注

前情回顾

第四层中我遇到了一个很新奇的力量叫做友元可以把一些人变成好朋友的神奇力量除此之外还学习到了类内声明函数类外进行定义的操作同时也踏入了第五层…

运算符重载

黑黝黝的洞口一个人影在缓缓出现“我就知道你肯定可以掌握友元的这次需要你掌握另一种重载的力量——运算符重载祝你好运…”。“新的重载吗…”。

概念

  • 对已有的运算符进行重新定义赋予其另一种功能以适应各种不同的运算类型

为什么会出现运算符重载

  • 对于内置的数据类型编译器知道如何运算但是对于自定义类型是不知道如何去运算的这个时候就需要运算符重载本质上是写一个函数来告诉编译器。

运算符重载中函数名格式

  • 对于运算符重载中上面提到本质上是写一个函数不同的人对于函数的命名方式是不一样的这样编译器也不好识辨这个函数是不是在实现运算符重载所以编译器提供了一个固定的格式
  • operator+这里这个加号可以替换成别的符号当你要对什么符号进行运算符重载时就用什么符号

加减运算符重载

作用

  • 实现两个自定义数据类型的相加减运算

实现

上面提到对于内置数据类型编译器可以知道如何去运算而自定义类型是不知道的那现在有一个类它有三个对象其中一个对象等于其他两个对象加起来要怎么实现可以先验证直接用+能不能进行

#include<iostream>
using namespace std;

class A
{
public:
	A()
	{

	}
	A(int a, int b)
	{
		_a = a;
		_b = b;
	}
	int _a;
	int _b;
};

void test1()
{
	A a1(10, 10);
	A a2(10, 10);
	A a3;
	a3 = a1 + a2;
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述
报错了没有与这些操作数匹配的“+”运算符这个错误说明了编译器是不知道对象内部怎么进行加减的那设计一个函数函数名字用上面提到的operate+

#include<iostream>
using namespace std;

class A
{
public:
	A()
	{

	}
	A(int a, int b)
	{
		_a = a;
		_b = b;
	}
	A operator+(A &a1)
	{
		A tmp;
		tmp._a = this->_a + a1._a;
		tmp._b = this->_b + a1._b;
		return tmp;
	}
	int _a;
	int _b;
};

void test1()
{
	A a1(10, 10);
	A a2(10, 10);
	A a3;
	a3 = a1 + a2;
	cout << a3._a<<"   "<< a3._b;
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述
其实这中写法的本质还是调用函数即

  • a3=a1+a2 == a3=a1.operator+(a2)

同时也可以把这个改成类外的全局函数这个时候传参就需要传两个内部改一下

#include<iostream>
using namespace std;

class A
{
public:
	A()
	{

	}
	A(int a, int b)
	{
		_a = a;
		_b = b;
	}
	//A operator+(A &a1)
	//{
	//	A tmp;
	//	tmp._a = this->_a + a1._a;
	//	tmp._b = this->_b + a1._b;
	//	return tmp;
	//}
	int _a;
	int _b;
};
A operator+(A& a1, A& a2)
{
	A tmp;
	tmp._a = a1._a + a2._a;
	tmp._b = a1._b + a2._b;
	return tmp;
}

void test1()
{
	A a1(10, 10);
	A a2(10, 10);
	A a3;
	a3 = a1 + a2;
	cout << a3._a<<"   "<< a3._b;
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述
也是可以正常跑起来的。
减号同理与加号实现原理一致只需要把+换成-。

#include<iostream>
using namespace std;

class A
{
public:
	A()
	{

	}
	A(int a, int b)
	{
		_a = a;
		_b = b;
	}
	//A operator+(A &a1)
	//{
	//	A tmp;
	//	tmp._a = this->_a + a1._a;
	//	tmp._b = this->_b + a1._b;
	//	return tmp;
	//}
	int _a;
	int _b;
};
A operator-(A& a1, A& a2)
{
	A tmp;
	tmp._a = a1._a - a2._a;
	tmp._b = a1._b - a2._b;
	return tmp;
}

void test1()
{
	A a1(10, 10);
	A a2(10, 10);
	A a3;
	a3 = a1 - a2;
	cout << a3._a<<"   "<< a3._b;
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述

左移运算符重载

作用

  • 可以输出自定义的数据类型

左移运算符是什么

  • 左移运算为程序员调用cout的时候会在后面加“<<”这个就是左移运算符

实现

同样可以直接用cout来进行只用类就把类内属性都打印出来吗

#include<iostream>
using namespace std;

class A
{
public:
	A()
	{

	}
	A(int a, int b)
	{
		_a = a;
		_b = b;
	}
	//A operator+(A &a1)
	//{
	//	A tmp;
	//	tmp._a = this->_a + a1._a;
	//	tmp._b = this->_b + a1._b;
	//	return tmp;
	//}
	int _a;
	int _b;
};
A operator-(A& a1, A& a2)
{
	A tmp;
	tmp._a = a1._a - a2._a;
	tmp._b = a1._b - a2._b;
	return tmp;
}

void test1()
{
	A a1(10, 10);
	A a2(10, 10);
	A a3(0, 0);
	a3 = a1 - a2;
	cout << a3 << endl ;
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述

明显是不可以的那要怎么样进行改造呢如果是成员函数呢传参和返回类型是什么返回类型暂定为void那参数呢cout吗那传参cout简化就变成了

  • 对象<<cout

放的顺序不一样所以成员函数无法实现那就用全局函数用之前需要探究一个事情cout是什么类型转到定义看一下

在这里插入图片描述
cout的类型就是ostream那类型解决了还有什么注意事项吗有并且很重要

  • 对于全局来说只有一个cout所以cout是需要进行引用的对象也是需要进行引用才可以。
#include<iostream>
using namespace std;

class A
{
public:
	A()
	{

	}
	A(int a, int b)
	{
		_a = a;
		_b = b;
	}
	//A operator+(A &a1)
	//{
	//	A tmp;
	//	tmp._a = this->_a + a1._a;
	//	tmp._b = this->_b + a1._b;
	//	return tmp;
	//}
	int _a;
	int _b;
};
A operator-(A& a1, A& a2)
{
	A tmp;
	tmp._a = a1._a - a2._a;
	tmp._b = a1._b - a2._b;
	return tmp;
}
void operator<<(ostream& cout, A& a3)
{
	cout << a3._a << "   " << a3._b;
}
void test1()
{
	A a1(10, 10);
	A a2(10, 10);
	A a3(0, 0);
	a3 = a1 - a2;
	cout << a3 << endl;
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述
为什么这里还是有报错对于cout这种能一直在后面追加编程称作链式编程在前面的this指针中提到过一种用途这里也要用到因为返回的是void所以对于endl来说前面的就不是cout所以就不能进行输出那这里就需要返回一个coutcout的类型同时记得加引用

#include<iostream>
using namespace std;

class A
{
public:
	A()
	{

	}
	A(int a, int b)
	{
		_a = a;
		_b = b;
	}
	//A operator+(A &a1)
	//{
	//	A tmp;
	//	tmp._a = this->_a + a1._a;
	//	tmp._b = this->_b + a1._b;
	//	return tmp;
	//}
	int _a;
	int _b;
};
A operator-(A& a1, A& a2)
{
	A tmp;
	tmp._a = a1._a - a2._a;
	tmp._b = a1._b - a2._b;
	return tmp;
}
ostream& operator<<(ostream& cout, A& a3)
{
	cout << a3._a << "   " << a3._b;
	return cout;
}
void test1()
{
	A a1(10, 10);
	A a2(10, 10);
	A a3(0, 0);
	a3 = a1 - a2;
	cout << a3 << endl;
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述

递增递减运算符

作用

  • 通过重载递增递减预算符实现自己类内的整型数据

实现

前置

前置的递增递减是前++- -在使用所以可以先在实现的函数内部先进行++- -在返回引用这里为什么要返回引用呢如果不返回引用那就是对局部这个变量进行了++- -多次使用++- -本身只会生成一次因为不是引用会产生拷贝把数据拷贝到新的空间上

  • 使用引用
#include<iostream>
using namespace std;

class A
{
public:
	A()
	{

	}
	A(int a, int b)
	{
		_a = a;
		_b = b;
	}
	A& operator++()
	{
		this->_a++;
		this->_b++;
		return *this;
	}
	//A operator+(A &a1)
	//{
	//	A tmp;
	//	tmp._a = this->_a + a1._a;
	//	tmp._b = this->_b + a1._b;
	//	return tmp;
	//}
	int _a;
	int _b;
};
A operator-(A& a1, A& a2)
{
	A tmp;
	tmp._a = a1._a - a2._a;
	tmp._b = a1._b - a2._b;
	return tmp;
}
ostream& operator<<(ostream& cout, A& a3)
{
	cout << a3._a << "   " << a3._b;
	return cout;
}
void test1()
{
	A a1(10, 10);
	A a2(10, 10);
	A a3(0, 0);
	a3 = a1 - a2;
	cout << ++(++a3) << endl;
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述

  • 不使用引用
#include<iostream>
using namespace std;

class A
{
public:
	A()
	{

	}
	A(int a, int b)
	{
		_a = a;
		_b = b;
	}
	A operator++()
	{
		this->_a++;
		this->_b++;
		return *this;
	}
	//A operator+(A &a1)
	//{
	//	A tmp;
	//	tmp._a = this->_a + a1._a;
	//	tmp._b = this->_b + a1._b;
	//	return tmp;
	//}
	int _a;
	int _b;
};
A operator-(A& a1, A& a2)
{
	A tmp;
	tmp._a = a1._a - a2._a;
	tmp._b = a1._b - a2._b;
	return tmp;
}
ostream& operator<<(ostream& cout, A& a3)
{
	cout << a3._a << "   " << a3._b;
	return cout;
}
void test1()
{
	A a1(10, 10);
	A a2(10, 10);
	A a3(0, 0);
	a3 = a1 - a2;
	cout << ++(++a3) << endl;
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述
直接是报错的。
前置递减实现也相同将++换成–即可。

后置

当定义后置++的时候发现与前置++使用的是一样的名字发现了重定义那这个时候怎么办可以在参数中写一个int用于区分这个int属于占位参数用于区分前置递增和后置递增编译器是只认int的对于后置递增应该记录初始结果如果在递增返回初始结果这个时候应该返回值而不是引用因为返回的是一个局部变量如果返回引用就会非法访问

  • 不是用引用
#include<iostream>
using namespace std;

class A
{
public:
	A(int a)
	{
		_a = a;
	}
	//后置++
	A operator++(int)
	{
		int a = this->_a++;
		return a;
	}
	int _a;
};
void test1()
{
	A a1(10);
	cout << a1._a++ << endl;
	cout << a1._a << endl;
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述

  • 是引用
#include<iostream>
using namespace std;

class A
{
public:
	A(int a)
	{
		_a = a;
	}
	//后置++
	A& operator++(int)
	{
		int a = this->_a++;
		return a;
	}
	int _a;
};
void test1()
{
	A a1(10);
	cout << a1._a++ << endl;
	cout << a1._a << endl;
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述

赋值运算符重载

  • 其实在C++中编译器一般会给一个类默认提供四个函数
  1. 默认构造函数无参函数体为空
  2. 默认析构函数无参函数体为空
  3. 默认拷贝函数对属性进行浅拷贝
  4. 赋值运算符对属性进行浅拷贝

注意

  • 当这个时候属性内的值有属性指向堆区时赋值操作符也会产生深拷贝和浅拷贝问题

编译器提供的是浅拷贝这个时候在析构函数内进行delete释放内存时会出现内存释放两次所以这个时候operator=修改成深拷贝即可注意在赋值操作符之前应该先判断赋值左侧值内堆区是否有数据有数据要先释放干净在进行深拷贝记得返回值要返回自身

#include<iostream>
using namespace std;

class A
{
public:
	A()
	{
		p = new int;
	}
	~A()
	{
		delete p;
		p = NULL;
	}
	void operator=(A& a)
	{
		if (p != NULL)
		{
			p = NULL;
		}
		p = new int(*a.p);
	}
	int* p;
};

void test1()
{
	A a;
	*a.p = 10;
	A b;
	b = a;
	cout << *b.p << endl;
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述

关系运算符重载

作用

  • 可以人两个自定义类型进行比较操作

实现

只用对比每一组属性是否相等相等返回真不相等返回假

#include<iostream>
using namespace std;

class A
{
public:
	A(int a, char c)
	{
		_a = a;
		_c = c;
	}
	bool operator==(A& a)
	{
		if (_a == a._a && _c == a._c)
		{
			return 1;
		}
		return 0;
	}
	int _a;
	char _c;
};
void test1()
{
	A a(10, 'c');
	A b(10, 'c');
	if (a == b)
	{
		cout << "a=b" << endl;
	}
	else
	{
		cout << "a!=b" << endl;
	}
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述

函数调用运算符重载

  • 函数调用操作符()也可以重载
  • 由于重载后调用的方式和函数本身的调用相似所以也被称为仿函数
  • 仿函数没有固定写法函数体内可以写任何。

事例

#include<iostream>
using namespace std;

class A
{
public:
	void operator()()
	{
		cout << "仿函数调用" << endl;
	}
};
void test1()
{
	A a;
	a();
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述

第二种重载掌握突破

面前的石碑碎去露出后面黑黝黝的洞口…

本章知识点图片形式

在这里插入图片描述

😘预知后事如何关注新专栏和我一起征服C++这座巨塔
🚀专栏C++爬塔日记
🙉都看到这里了留下你们的👍点赞+⭐收藏+📋评论吧🙉

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: c++