栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

day07 c++复习,运算符重载,详解查询资料(便于理解)版

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

day07 c++复习,运算符重载,详解查询资料(便于理解)版

 符号重载

运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型

 比如加号,加号可以运算两个整形的数据,但是可以运算两个class的数据嘛?是不能的,所以我们进行重载,让他可以适应两个class的数据

造成这样的原因,是因为C语言的一个问题,它太简洁了。仅增加、修改或删除一个字符就会使原先的程序变成另外一个仍然有效却全然不同的程序。

在C语言中,许多符号是被重载的——在不同的上下文环境里有不同的意义。甚至有些关键字也被重载而具有好几种意义。因此学会运算符重载在项目中有重大意义

因此

【c】C语言中符号的重载_Mysterious superstar的博客-CSDN博客_c 符号重载

这一篇文章中有介绍符号重载的的意义,内容简介明了

​​​​​​c语言全局变量符号,C中的符号重载——C语言系列(2)_weixin_39871649的博客-CSDN博客

这是两个容易造成混乱的运算符,建议仔细查看。

下面进行运算符的详细实例学习

加号运算符重载

作用:实现两个自定义数据类型相加的运算

怎么实现呢?我感觉还是两个不同类型的数据,分别赋值给一个类型临时数据,使用地址传递,然后在同一个类内运算后,在返回。

如图,重点理解过程

​

 就完成了不同类型的数据类型运算,但随着技术进步,这步骤被简化,并被统一规范,后来也就是运算符重载

简化后,person p3= operator+(p1+p2);大概就是这个意思。变量名未必正确,

 

 不报错了

 

 

 预算符重载,也可以发生函数重载。

注意这张图,使用了变量加int, 

它可以运算嘛?编译器还是不知道如何运算的。

但是我们可以写一个~,就可以了

  完整代码段

#include 
#include
using namespace std;
//加号运算符重载,
class person
{
public:
	//1、成员函数重载+号
	//person  operator+(person& p)
	//{
	//	person temp;
	//	temp.m_a = this->m_a + p.m_a;
	//	temp.m_b = this->m_b + p.m_a;
	//	return temp;
	//}
	int m_a;
	int m_b;
};
//全局函数重载+号 变量加上变量的
person operator+(person& p1, person& p2)
{
	person temp;
	temp.m_a = p1.m_a + p2.m_a;
	temp.m_b = p1.m_b + p2.m_b;
	return temp;
}
//全局函数重载+号 变量加上int整型数据的
person operator+ (person& p1, int num)
{
	person temp;
	temp.m_a = p1.m_a + num;
	temp.m_b = p1.m_b + num;
	return temp;
}
void test01()
{
	person p1;
	p1.m_a = 10;
	p1.m_b = 10;
	person p2;
	p2.m_a = 10;
	p2.m_b = 10;

	person p3 = p1 + p2;
	person p4 = p1 + 10;
	cout << "p3.m_a=" << p3.m_a << endl;
	cout << "p3.m_b=" << p3.m_b << endl;
	cout << "p4.m_b=" << p4.m_b << endl;
}



int main() {
	test01();
	system("pause");
	return 0;
}

 我学了一个小时,有点想吐了。建议找支笔,画一画,理解一下,然后多吃糖。

总结1:对于内置的数据类型的表达式的的运算符是不可能改变的

总结2:不要滥用运算符重载

 左移运算符

作用:可以输出自定义数据类型

什么是左移运算符?  是<<,对就是cout<<"  "  <

我也不理解ostream是啥,只是说输出流整形,为什么这么写也不明白,上csgn也没查到,现有语法体系下只能这样写,死记硬背吧

 有趣的是,他这个也可以采用链式思想

 

 但是全局变量重载<<出现个问题,如何访问类内的私有权限内容?

使用友元

完整代码段

#include 
#include
using namespace std;

//左移运算符重载
class person
{
	//利用成员函数重载,左移运算符 p.operatpr<<(cout) 简化版本,p< 
递增运算符重载 

理解重载运算符的作用后,接下来不理解的死记硬背即可,因为涉及计算机原理了

 所以要重载<<

 怎么解决这个重载运算符后,依旧存在的报错呢?加上友元既可。

 不报错了

重载后置++运算符

 

 因为作用域和名称都一致,编译器不能辨认前置和后置的区别

因此()内加上引入参数,来增加点不一致。

    //这里有一个逻辑问题,怎么样进行++,前置可以进行++,因为可以后知道值,但是后置进行++呢?
        // 要先引入一个临时的值接收,在这个值上++。

 

 完整代码段

//重载递增运算符

//自定义整形
class my_int_teger
{
public:
	friend ostream& operator<<(ostream& cout, my_int_teger my_int);
	my_int_teger()
	{
		m_num = 0;
	}
	//重载前置++运算符
	my_int_teger & operator++()
	{
		//先进行++的运算,
		m_num++;

		//在将自身做一个返回
		return *this;
	}
	//重载后置++运算符
	my_int_teger  operator++(int )//这样编译器就会认为这是一个后置的,因为int是个占位参数
	{
	
//先,记录当时的结果
		my_int_teger temp = *this;
//后递增
		m_num++;
		//再返回
		return temp;
	}


private:
	int m_num;
};

//重载左移运算符
ostream& operator<<(ostream& cout, my_int_teger my_int)
{
	cout << ++my_int.m_num;
	return cout;
}

void test01()
{
	my_int_teger my_int;
	cout << my_int << endl;//报错原因,因为我们输出的是一个自定义数据类型
}
void test02()
{
	my_int_teger my_int;
	cout << my_int++ < 

有时间自己写一个-- 的运算符重载,

#include 
#include
using namespace std;

//重载递增运算符

//自定义整形
class my_int_teger
{
public:
	friend ostream& operator<<(ostream& cout, my_int_teger my_int);
	my_int_teger()
	{
		m_num = 0;
	}
	//重载前置++运算符
	my_int_teger & operator--()
	{
		//先进行++的运算,
		m_num--;

		//在将自身做一个返回
		return *this;
	}
	//重载后置++运算符
	my_int_teger  operator--(int )//这样编译器就会认为这是一个后置的,因为int是个占位参数
	{
	
//先,记录当时的结果
		my_int_teger temp = *this;
//后递增
		m_num--;
		//再返回
		return temp;
	}


private:
	int m_num;
};

//重载左移运算符
ostream& operator<<(ostream& cout, my_int_teger my_int)
{
	cout << --my_int.m_num;
	return cout;
}

void test01()
{
	my_int_teger my_int;
	cout << my_int << endl;//报错原因,因为我们输出的是一个自定义数据类型
}
void test02()
{
	my_int_teger my_int;
	cout << my_int-- < 

这里偷懒了,直接换了下--就完成了,看程序员的真谛就是ctrl +x +v啊

赋值运算符重载

赋值运算符就是=

c++编译器至少给一个类添加4个函数

  1. 默认构造函数(无参,函数体为空)

  2. 默认析构函数(无参,函数体为空)

  3. 默认拷贝构造函数,对属性进行值拷贝

  4. 赋值运算符 operator=, 对属性进行值拷贝

 

 

 由于使用的是指针,所有在输出的时候,原值,实参随之改变

因为用的是指针去指向的内存地址,因此要用析构函数

 你要是真的这样写,编译器立马运行死给你看,因为这里是犯了大忌,同一内存地址被反复释放,之前析构那里有讲,为了解决这个问题,我们要重置赋值运算符,来形成差异,让指针指向两个内存地址。

 

 这是可以执行的,但是试试p3=p2=p1呢?就报错。

 因为p2返回的是void,要解决这个问题,采用链式的思想,让他自己返回对象本身

 

 

 为什么要写运算符重载?

因为编译器提供的是个浅拷贝,但是有些数据创建在堆区,如何释放这些堆区数据?

浅拷贝释放会重复释放同一位置的内存地址,使得程序崩溃。

就只能运算符重载了

//赋值运算符重载
class person
{
public:
	person(int age)
	{
	m_age = new int(age);//注意使用了new,把数据创建在了堆区
	}
	~person()//析构函数,开始释放
	{
		if (m_age != NULL)
		{
			delete m_age;
			m_age = NULL;
		}
	}
	//重载赋值运算符
	person&  operator=(person &p)
	{
	//应该先判断是否由属性在堆区,如果有先释放干净,然后再深拷贝
		if (m_age != NULL)
		{
			delete m_age;
			m_age == NULL;
		}
		//深拷贝
		m_age = new int(*p.m_age);
		return * this;
	}

	int *m_age;
};
void test01()
{

	person p1(18);

	person p2(20);
	person p3(30);
//小亮,整个活
	p3 = p1 = p2;
	cout << "p1的年龄为" << *p1.m_age << endl;
	cout << "p2的年龄为" << *p2.m_age << endl;
	cout << "p3的年龄为" << *p3.m_age << endl;
}

int main()
{
//int a = 10;
//int b = 20;
//int c = 30;
//c = b = a;
//	cout << "a = " << a << endl;
//	cout << "b = " << b << endl;
//	cout << "c = " << c << endl;

	test01();
	system("pause");
	return 0;
}
关系运算符重载

重载关系运算符,可以让两个自定义类型对象进行对比操作

关系运算符<、>、||、!=这一类符号

同理,也是各种类型数据进行比较

 

 关系符重载

其他的同理,不再赘述,代码用教程的了

class Person
{
public:
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	};

	bool operator==(Person & p)
	{
		if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	bool operator!=(Person & p)
	{
		if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
		{
			return false;
		}
		else
		{
			return true;
		}
	}

	string m_Name;
	int m_Age;
};

void test01()
{
	//int a = 0;
	//int b = 0;

	Person a("孙悟空", 18);
	Person b("孙悟空", 18);

	if (a == b)
	{
		cout << "a和b相等" << endl;
	}
	else
	{
		cout << "a和b不相等" << endl;
	}

	if (a != b)
	{
		cout << "a和b不相等" << endl;
	}
	else
	{
		cout << "a和b相等" << endl;
	}
}


int main() {

	test01();

	system("pause");

	return 0;
}
函数调用运算符重载
  • 函数调用运算符 () 也可以重载

  • 由于重载后使用的方式非常像函数的调用,因此称为仿函数

  • 仿函数没有固定写法,非常灵活

class MyPrint
{
public:
	void operator()(string text)
	{
		cout << text << endl;
	}

};
void test01()
{
	//重载的()操作符 也称为仿函数
	MyPrint myFunc;
	myFunc("hello world");
}


class MyAdd
{
public:
	int operator()(int v1, int v2)
	{
		return v1 + v2;
	}
};

void test02()
{
	MyAdd add;
	int ret = add(10, 10);
	cout << "ret = " << ret << endl;

	//匿名对象调用  
	cout << "MyAdd()(100,100) = " << MyAdd()(100, 100) << endl;
}

int main() {

	test01();
	test02();

	system("pause");

	return 0;
}

运算符重载到此结束,只是对各种类型的符号重载进行距离说明,并不是全部符号重载,因为那不是新手范围了,新手重点是理解运算符重载是什么?意义是什么?大概的类型?知道了,慢慢学,反正我是还不会,因此不能直接描述。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/976490.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号