c++学习——运算符重载

news2024/12/25 8:58:01

运算符重载

    • **运算符重载的概念**
    • **加号运算符重载**
    • **减号运算符重载**
    • **左移运算符重载**
    • **右移运算符重载**
    • **赋值运算符重载**
    • **关系运算符重载**
    • **前置加加和后置加加**

运算符重载的概念

1.运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。
2.运算符重载的目的是让语法更加简洁
3.运算符重载不能改变本来寓意,不能改变基础类型寓意
4.运算符重载的本质是另一种函数调用(是编译器去调用)
5.这个函数同一的名字叫operator
6.重载函数可以写成全局或成员函数
7.重载函数如果写成全局的,那么双目运算符左边的是第一个参数,右边是第二个参数
8.重载函数如果写成成员函数,那么双目运算符的左边是this,右边是第一个参数
9.不能改变运算符优先级,不能改变运算符的参数个数

在这里插入图片描述
短路规则是:与运算前面假就假后面无需判断,或者是或运算前面真就真后面无需判断
什么叫短路规则

加号运算符重载

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

class Maker
{
public:
	Maker(int id, int age)
	{
		this->id = id;
		this->age = age;
	}
	//写成成员函数,那么只需要一个参数,这个参数是加号的右边
	Maker operator+(Maker &m2)
	{
		Maker temp(this->id + m2.id, this->age + m2.age);
		return temp;
	}
public:
	int id;
	int age;
};

//全局方式  //2、编译器调用这个函数
//Maker operator+(Maker &p1,Maker &p2)//3、编译器检查参数是否对应
//{
//	Maker temp(p1.id + p2.id, p1.age + p2.age);
//	return temp;
//}

void test01()
{
	Maker m1(1, 20);
	Maker m2(2, 22);

	Maker m3 = m1 + m2;//1、编译器看到两个对象相加,那么编译器会去找有没有叫operator+的函数
	cout << "id:" << m3.id << "age:" << m3.age << endl;
	//复数加
	Maker m4 = m1 + m2 + m3;//先是m2+m3
	cout << "id:" << m4.id << "age:" << m4.age << endl;
}

//不同类型的加法运算符重载
class Student
{
public:
	Student()
	{
		mid = 0;
	}
	Student(int id)
	{
		mid = id;
	}
public:
	int mid;
};

//返回值是任意一个类都行
Maker operator+(Maker &m,Student &s)
{
	Maker tmp(m.id + s.mid, 20);//20随便传的一个参数
	return tmp;
}

Maker operator+(Student &s,Maker &m)
{
	Maker tmp(s.mid + m.id,20);//20随便传的一个参数
	return tmp;
}

void test()
{
	Maker m1(1, 18);
	Student s1(2);
	Maker m2 = m1 + s1;
	Maker m3 = s1 + m1;
}

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

在这里插入图片描述

减号运算符重载

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

class Maker
{
public:
	Maker(int id)
	{
		this->id = id;
	}
public:
	int id;

	//写成成员函数,那么只需要一个参数,这个参数是减号的右边
	Maker operator-(Maker &m2)
	{
		Maker tmp(this->id - m2.id);
		return tmp;
	}
};

int operator-(Maker &m, int b)
{
	return m.id - b;
}

void test()
{
	Maker m1(10);
	Maker m2(5);
	Maker m3 = m1 - m2;
	cout << m3.id << endl;

	int a = m3 - 5;
	cout << a << endl;
}

int main()
{
	test();
	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

左移运算符重载

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <string>

class Maker
{
	friend ostream& operator<<(ostream &out, Maker &m);
public:
	Maker(int id,string name)
	{
		this->id = id;
		this->name = name;
	}
private:
	int id;
	string name;
};

//1、形参和实参是一个对象
//2、不能改变库类中的代码
//3、ostream中把拷贝构造函数私有化了
//4、如果要和endl一起使用必须返回ostream的对象

//cout其实是个类
//void operator<<(ostream &out,Maker &m)
ostream& operator<<(ostream &out,Maker &m)
{
	cout << m.id << " " << m.name << endl;

	return out;
}

void test01()
{
	Maker m(10,"露琪亚");
	//对应的上面第一个void operator的注释
	//cout << m.id << endl;//现在就是err 因为返回的是void  
	cout << m << endl;
	cout << m;//返回的是void

	cout << endl;//endl是内联函数
	/*endl是一个函数
	operator<<(函数指针)
	operator<<(endl)
	*/
	cout << 10;//内部重载了基础数据类型
	cout << endl;

}

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

右移运算符重载

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include<string>

void test()
{
	int a;
	cin >> a;
	cout << a << endl;
}

class Maker
{
	friend istream &operator>>(istream &in, Maker &m);
public:
	Maker(string name, int age)
	{
		this->name = name;
		this->age = age;
	}
	int getAge()
	{
		return age;
	}
private:
	string name;
	int age;
};

istream &operator>>(istream &in, Maker &m)
{
	in >> m.age;
	in >> m.name;
	return in;
}

void test02()
{
	Maker m("悟空", 15);
	Maker m2("悟空", 15);
	cin >> m >> m2;

	cout << m.getAge() << endl;
	cout << m2.getAge() << endl;
}

int main()
{
	test02();
	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

赋值运算符重载

编译器默认给类提供了一个默认的赋值运算符重载函数
默认的赋值运算符重载函数进行了简单的赋值操作
当类有成员指针时,然后在构造函数中申请堆区空间,在析构函数中释放堆区空间

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

class Maker
{
public:
	Maker()
	{
		id = 0;
		age = 0;
	}
	Maker(int id, int age)
	{
		this->id = id;
		this->age = age;
	}
public:
	int id;
	int age;
};

void test()
{
	Maker m1(10, 20);
	Maker m2;

	m2 = m1;//赋值操作

	//默认的赋值运算符重载函数进行了简单的赋值操作
	cout << m2.id << " " << m2.age << endl;
}

class Student
{
public:
	Student(const char *name)
	{
		pName = new char[strlen(name) + 1];
		strcpy(pName, name);
	}

	//防止浅拷贝
	Student(const Student &stu)
	{
		pName = new char[strlen(stu.pName) + 1];
		strcpy(pName, stu.pName);
	}

	//重写赋值运算符重载函数
	
	Student &operator=(const Student &stu)
	//如果不返回&的话相当于是Student operator=s1 相当于调用了一次拷贝构造函数
	{
		//1.不能确定this->pName指向的空间是否能装下stu中的数据,所以先释放thist指向的空间
		if (this->pName != NULL)
		{
			delete[] this->pName;
			this->pName = NULL;
		}

		//2、申请堆区空间,大小由stu决定
		this->pName = new char[strlen(stu.pName) + 1];
		//3、拷贝数据
		strcpy(this->pName, stu.pName);
		//4、返回对象本身
		return *this;//*this返回的是对象的本身   s1 s2 s3
	}

	~Student()
	{
		if (pName!=NULL)
		{
			delete[] pName;
			pName = NULL;
		}
	}

	void printStudent()
	{
		cout << "pName:" << pName << endl;
	}
public:
	char *pName;
};

void test02()
{
	Student s1("卡卡罗特");
	Student s2("露琪亚");

	s1.printStudent();
	s2.printStudent();

	s1 = s2;//赋值操作  析构函数会导致同一块空间被释放两次
	//还会导致内存泄露

	s1.printStudent();
	s2.printStudent();

	//s1 = s2 = s3;
}

void test03()
{
	Student s1("a");
	Student s2("b");
	Student s3("c");

	s1 = s2 = s3;//赋值操作

	cout << &(s2 = s3) << endl;
	cout << &s2 << endl;
}

int main()
{
	//test02();
	test03();
	system("pause");
	return EXIT_SUCCESS;
}

关系运算符重载

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

class Maker
{
public:
	Maker()
	{
		id = 0;
		age = 0;
	}
	Maker(int id, int age)
	{
		this->id = id;
		this->age = age;
	}
	bool operator==(Maker &m)
	{
		if (this->id == m.id && this->age == m.age)
		{
			return true;
		}
		return false;
	}
	bool operator != (Maker &m)
	{
		if (this->id != m.id && this->age != m.age)
		{
			return true;
		}
		return false;
	}
public:
	int id;
	int age;
};

void test01()
{
	Maker p1(1, 20);
	Maker p2;
	if (p1 == p2)
	{
		cout << "真" << endl;
	}
	else
	{
		cout << "假" << endl;
	}

	if (p1 != p2)
	{
		cout << "真" << endl;
	}
	else
	{
		cout << "假" << endl;
	}
}

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

在这里插入图片描述

前置加加和后置加加

/你的第二个operator++返回了一个临时变量,这个在C++里面是一个右值(简单来说就是只能放在 = 号右边)
而你重载的 << 操作符号第二个参数是一个非const的引用,非const的引用需要一个左值(可以放在 = 号左边,可以赋值)来初始化,因此报错
解决办法很简单,把你重载的 << 符号第二个参数加上const修饰即可。加了const修饰的引用可以用右值来初始化
/

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <string>

void test()
{
	int a = 1;
	cout << ++a << endl;
	cout << a++ << endl;
	cout << a << endl;
	++(++a);
}

class Maker
{
	friend ostream &operator<<(ostream &out,  Maker const  &m);
public:
	Maker(int a)
	{
		this->a = a;
		//cout << "1" << endl;
	}

	//重载前置++
	Maker &operator++()
	{
		++this->a;
		return *this;
	}

	//重载后置++
	//这里不用引用  是因为
	//如果返回引用这里是返回局部的引用    在这个函数执行完时,被释放掉了
	Maker operator++(int)//区分后置++  //占位参数,必须是int
	{
		//后置++,先返回,后++
		Maker tmp(*this);  //1、*this里面的值a是等于2的
		++this->a;   //这个对象的a是等于3的
		return tmp;//返回的是右值常量  零时变量  调用一次构造函数
	
		/*你的第二个operator++返回了一个临时变量,这个在C++里面是一个右值(简单来说就是只能放在 = 号右边)
		而你重载的 << 操作符号第二个参数是一个非const的引用,非const的引用需要一个左值(可以放在 = 号左边,可以赋值)来初始化,因此报错
		解决办法很简单,把你重载的 << 符号第二个参数加上const修饰即可。加了const修饰的引用可以用右值来初始化*/

		/*	cout << "后置加加" << endl;
		return Maker(10);*/
	}

private:
	int a;
};

ostream &operator<<(ostream &out, Maker const  &m)
{
	out << m.a << endl;
	return out;
}

void test01()
{
	Maker m1(1);
	//cout << m1 << endl;//1
	//cout << ++m1 << endl;//2

	cout << (m1++) << endl;//2    
	//cout << m1 << endl;//3  
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/612866.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Boot 框架整体启动流程详解

基于Spring Boot 版本&#xff1a;3.1 Java: 17 Spring Boot 的入口即为xxApplication类的main方法&#xff1a; SpringBootApplication public class SpringBootDemoApplication {public static void main(String[] args) {SpringApplication.run(SpringBootDemoApplication.…

Android 13 wifi adb设置固定端口解决

Android 13 wifi adb设置固定端口解决 本文只管解决介绍不做代码层面具体分析。 文章目录 Android 13 wifi adb设置固定端口解决一、前言二、设置wifi 固定端口号三、打开 "无线调试"1、手动打开设置里面的开发者选项 里面的“无线调试”2、通过命令设置打开 "…

想面试Java后端,至少这些你都要会吧

跨越Java后端面试的最重要关卡&#xff0c;就是对技术知识的准备。但难点在于&#xff0c;后端技术栈的内容繁杂&#xff0c;你需要掌握一个广泛的领域。那么&#xff0c;为了保证你能够顺利面试Java后端岗位&#xff0c;下面分享我认为你必须要掌握的技术&#xff1a; 1. Jav…

【实验练习】基于SVM的实现鸢尾花(Iris)数据集分类 (Python实现)

题目 采用SVM方法实现鸢尾花(Iris)数据集分类 数据集 iris.name是关于数据集的属性说明&#xff1b; iris.data是实际的数据集&#xff0c;它包含三类数据&#xff0c;每类数据有50条数据。 要求 训练集&#xff1a;选取Iris数据集中80%的数据&#xff0c;即120个数据&…

小程序容器技术:数字门户的创新引擎

数字门户是指提供一站式访问和集成多个在线服务、信息和资源的网络平台。它通常是一个网站或应用程序&#xff0c;为用户提供广泛的功能和服务&#xff0c;如新闻、天气预报、电子邮件、在线购物、社交媒体、银行服务、电子支付、在线学习、政府服务等。数字门户的目标是通过集…

Laravel 招聘系统 - 求职者和雇主的解决方案

您是否正在寻找一个将求职者和雇主联系起来的解决方案&#xff1f;那就不要再找了&#xff01;我们隆重推出 Laravel 招聘板&#xff0c;这是一个使用 Laravel 9.x 框架构建的尖端招聘板脚本。凭借其简洁而优雅的设计&#xff0c;该脚本旨在创建一个用于广告职位空缺、寻找合适…

【Python小技巧】Python操控Chrome浏览器实现网页打开、切换、关闭(送独家Chrome操作打包类源码、Chrome浏览器Cookie在哪里?)

文章目录 前言一、什么时候需要用Python控制浏览器&#xff1f;二、下载Chrome浏览器驱动文件1. 安装Chrome浏览器并查看版本2. 下载浏览器驱动文件3. 解压到python编译器目录&#xff08;python.exe所在目录&#xff09; 三、Python控制Chrome浏览器&#xff08;附源代码&…

基于国产RK3588+多路H.265视频编解码 转码 3U VPX 方案

一、概述 3U VPX音视频转码模块是信迈科技推出的基于RK3588平台用于音视频的编解码、转码&#xff0c;本模块SDI视频、模拟音频输入&#xff0c;视频进行分辨率和帧率的变换&#xff0c;音频进行采样率和码率等的变换&#xff0c;网口输入的视频流进行解码或者转码&…

Linux——进程优先级环境变量

目录 1、进程优先级 1.1 基本概念 1.2 查看系统进程 1.3 PRI and NI 1.4 PRI vs NI 1.5 查看进程优先级的命令 1.6 其他概念 2、环境变量 2.1 基本概念 2.2 常见环境变量 2.3 查看环境变量方法 2.4 测试PATH 2.5 测试HOME 2.6 和环境变量相关的命令 2.7 环境变量…

Springboot配置文件中的明文密码漏洞

目录 一、背景 二、本地修复测试 1、maven中引入jasypt 2、编写加密解密工具类 3、修改配置文件&#xff0c;增加秘钥 4、秘钥放在启动项 三、生产实现 1、升级打包代码 2、生产yml修改明文密码处 3、修改启动命令 一、背景 最近接收到网安的系统安全…

c++类和对象【3】(static成员,友元内部类,匿名对象等)

文章目录 1.友元函数1.1友元函数1.2友元类 2内部类3.匿名对象4.拷贝对象的一些编译器优化5.static成员 1.友元函数 我们在类外面去访问类里的私有成员&#xff0c;就要突破类的访问限定因此就有了友元&#xff0c;它提供了一种突破封装的方式&#xff0c;但是友元会增加耦合度…

GPT时代,一定要收藏的结构化提问技巧

有一种被称为“SMART”的结构化提问方法&#xff0c;可以帮助你更好的组织和明确提出的问题。“SMART”是一个缩写&#xff0c;它代表了以下几个关键元素&#xff1a; S&#xff1a;Specific&#xff08;具体&#xff09; 确保问题具体明确&#xff0c;避免模糊或含糊不清的表…

基于SVPWM调制的三相整流器_Simulink仿真模型

文章目录 模型总览特性功能实现输入三相交流电压220Vac 经过三相整流器进行功率变换&#xff0c;输出电压750V&#xff0c;输出功率10kW&#xff0c;同时实现功率因数校正/PFC功能&#xff08;控制输入电流与输入电压同相且为正弦电流&#xff09;&#xff0c;输入电流THD为1.3…

spring cloud搭建(zuul)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

路径规划算法:基于黏菌优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于黏菌优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于黏菌优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化算法黏菌…

一百二十二、Git——Git上传代码(完善中)

方式一、用IDEA 第一步&#xff0c;IEDA拉项目 File——New——Project from Version Control——Git 输入URL&#xff0c;选择Directory&#xff0c;点击clone 第二步&#xff0c;把上传文件拉到IDEA项目&#xff0c;然后选中文件&#xff0c;右击Git,选择Reposity,如果上传…

中国人口增长预测

目录 问题分析 模型建立 Logistic模型 Leslie模型 模型求解 问题一 问题二 问题三 问题分析 问题 基本假设 &#xff08;1&#xff09;不考虑移民对人口总数的影响 &#xff08;2&#xff09;超过90岁按照90岁计算 &#xff08;3&#xff09;在较短时间内&#xff0c;平均…

深度学习预预训练与MMPretrain

MMPretrain算法库 优势&#xff1a; 含有各种主干网络模型自监督学习功能多模态学习功能丰富的数据集含有训练技巧和策略易用&#xff0c;例如可解释性分析、推理api 包含多种丰富任务的开箱即用推理api 图像分类图像语义描述视觉问答视觉定位检索 安装步骤 配置文件中含有…

python 社区发现算法

转载&#xff1a;这个Python库超级棒啊&#xff0c;包含Louvain 算法、Girvan-Newman 算法等多种社区发现算法&#xff0c;还具有可视化功能_11205354的技术博客_51CTO博客 熟知社区发现算法&#xff0c;你不能错过这个 Python 库。它涵盖 Louvain 算法、Girvan-Newman 算法等…

Java基础(项目2)——项目案例:控制台的一个云就业平台项目【应聘+招聘】

目录 引出项目的分层固定的流程反思1.entity --- 实体类2.dao ---数据库的CRUD【进化到Spring的JdbcTemplate】以职位投递的dao为例---进化到Spring的JdbcTemplate&#xff1a; 3.service --- 组织代码的业务【进化到servlet调用service】4.util ---需要用到的工具【进化到duri…