【C++学习】类和对象 | 运算符重载 | 赋值运算符重载

news2024/11/24 10:02:34

 写在前面:

上一篇文章我们学了拷贝构造,还探索了操作符重载的使用,

如果有兴趣可以去看看:http://t.csdn.cn/dkD1g

今天我们接着学习类和对象相关的知识。

目录

 写在前面:

1. 运算符重载

2. 赋值运算符重载

写在最后:


1. 运算符重载

来看这段代码:

#include <iostream>
using namespace std;

class Date {
public:
	Date(int year = 2023, int month = 6, int day = 30) {
		_year = year;
		_month = month;
		_day = day;
	}

	void Print() {
		cout << _year << "-" << _month << "-" << _day << endl;
	}

//private:
	int _year;
	int _month;
	int _day;
};

bool operator<(const Date& x, const Date& y) {
	if (x._year < y._year) return true;
	else if (x._year == y._year && x._month < y._month) return true;
	else if (x._year == y._year && x._month == y._month && x._day < y._day) return true;
	else false;
}

int main()
{
	Date d1(2023, 1, 1);
	Date d2(2023, 2, 2);
	cout << (d1 < d2) << endl;

	return 0;
}

如果我们想让这个日期类比较大小,

我们可以专门写一个比较大小的函数来完成,

但是学习了操作符重载之后,我们就能直接使用操作符重载来完成比较了,

但是,如果把操作符重载放在类外面,那我们必须把类的成员变量放到public,

这样就破坏了类的封装性了,那如果我们直接把这个函数放进类内呢?

来看代码:

#include <iostream>
using namespace std;

class Date {
public:
	Date(int year = 2023, int month = 6, int day = 30) {
		_year = year;
		_month = month;
		_day = day;
	}

	bool operator<(const Date& x, const Date& y) {
		if (x._year < y._year) return true;
		else if (x._year == y._year && x._month < y._month) return true;
		else if (x._year == y._year && x._month == y._month && x._day < y._day) return true;
		else false;
	}

	void Print() {
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2023, 1, 1);
	Date d2(2023, 2, 2);
	cout << (d1 < d2) << endl;

	return 0;
}

编译器就出现了一个报错:

说这个运算符函数的参数太多了,

这是为什么? 

因为类内的成员函数有隐藏的this指针,

所以我们就留一个参数用来比较,另一个参数就是this指针,

来看代码:

#include <iostream>
using namespace std;

class Date {
public:
	Date(int year = 2023, int month = 6, int day = 30) {
		_year = year;
		_month = month;
		_day = day;
	}

	bool operator<(const Date& x) {
		if (_year < x._year) return true;
		else if (_year == x._year && _month < x._month) return true;
		else if (_year == x._year && _month == x._month && _day < x._day) return true;
		else false;
	}

	void Print() {
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2023, 1, 1);
	Date d2(2023, 2, 2);
	
	cout << (d1 < d2) << endl;
	cout << d1.operator<(d2) << endl;

	return 0;
}

实际上 d1 < d2 这个表达式,他本质上就是一个函数调用,

也就是 d1.operator<(d2) 。

要注意:

操作符重载只能重载C++存在的操作符,不能自创;

重载操作符必须有一个类类型参数;

用于内置类型的运算符,不能改变其含义;

作为类类型重载的时候,形参看起来比操作数少1个,实际上第一个参数是隐藏的this指针;

注意!(   .*   ::   sizeof   ?:   .   )这5个运算符是不能重载的!!!

2. 赋值运算符重载

来看这段代码:

#include <iostream>
using namespace std;

class Date {
public:
	Date(int year = 2023, int month = 6, int day = 30) {
		_year = year;
		_month = month;
		_day = day;
	}

	void Print() {
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2023, 1, 1);
	Date d2;

	//如果我们使用一个对象赋值一个对象,就会调用赋值运算符重载
	d1 = d2;

	return 0;
}

这个时候就需要用到赋值运算符重载,

不过这里要注意的是,拷贝构造跟赋值运算符重载是不一样的,

拷贝构造是用一个已经存在的对象初始化另一个对象,

而赋值运算符重载是两个已经存在的对象之间的复制拷贝。

那该怎么实现呢?

来看代码:

#include <iostream>
using namespace std;

class Date {
public:
	Date(int year = 2023, int month = 6, int day = 30) {
		_year = year;
		_month = month;
		_day = day;
	}

	void operator=(const Date& x) {
		_year = x._year;
		_month = x._month;
		_day = x._day;
	}

	void Print() {
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2023, 1, 1);
	Date d2;

	//如果我们使用一个对象赋值一个对象,就会调用赋值运算符重载
	d1 = d2;

	return 0;
}

这样真的就行了吗?

运行编译器也没有报错,好像成功了,但是,

如果你创建了三个对象的时候,你发现:

他不能支持连续赋值,

不支持:d1 = d2 = d3 这种操作,

要想让他支持连续赋值,我们需要给这个赋值运算符重载函数添加返回值:

来看代码:

#include <iostream>
using namespace std;

class Date {
public:
	Date(int year = 2023, int month = 6, int day = 30) {
		_year = year;
		_month = month;
		_day = day;
	}

	// d1 = d2
	Date& operator=(const Date& x) {
		_year = x._year;
		_month = x._month;
		_day = x._day;
		return *this;
	}

	void Print() {
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2023, 1, 1);
	Date d2;

	//如果我们使用一个对象赋值一个对象,就会调用赋值运算符重载
	d1 = d2;

	return 0;
}

这样子我们就能让赋值成功的d1的值返回了,

并且,我们的d1对象在出了函数作用域之后还在吗,还在,

所以我们使用引用返回来提高效率,减少拷贝。

实际上还有一种可能的情况,

如果有人做这样的操作呢:d1 = d1 自己调用自己呢?

所以我们最好给这段代码也加上一点判断:

#include <iostream>
using namespace std;

class Date {
public:
	Date(int year = 2023, int month = 6, int day = 30) {
		_year = year;
		_month = month;
		_day = day;
	}

	// d1 = d2
	Date operator=(const Date& x) {
		if (this == &x) { //如果是自己给自己赋值,就直接返回了
			_year = x._year;
			_month = x._month;
			_day = x._day;
		}
		return *this;
	}

	void Print() {
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2023, 1, 1);
	Date d2;

	//如果我们使用一个对象赋值一个对象,就会调用赋值运算符重载
	d1 = d2;
	d1 = d1;

	return 0;
}

如果我们没有实现赋值重载函数,

编译器会默认生成一个,而这个默认生成的跟拷贝构造的规则是一样的:

对于内置类型的成员,会做值拷贝或者说浅拷贝;

而对于自定义类型成员,会调用他的赋值赋值重载。

所以,如果是像栈这样需要深拷贝的对象,我们也需要自己实现赋值重载。

这里要注意一下:

赋值重载不能重载到全局,因为他是默认成员函数,

如果我们没有实现,编译器会自动帮我们实现的,如果我们写到全局,

就会跟默认生成的发生冲突。

写在最后:

以上就是本篇文章的内容了,感谢你的阅读。

如果感到有所收获的话可以给博主点一个哦。

如果文章内容有遗漏或者错误的地方欢迎私信博主或者在评论区指出~

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

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

相关文章

Nginx常用模块

Nginx常用模块 文章目录 Nginx常用模块1.Nginx常用模块1.1.Nginx目录索引/下载模块1.1.1.配置autoindex语法1.1.2.autoindex配置实例1.1.3上传资源1.1.4.autoindex_exact_size配置语法1.1.5.修改配置文件1.1.6.再次访问1.1.7.修改日期1.1.8.autoindex_localtime语法格式1.1.9.修…

【C51】基于51单片机的出租车计价器设计

摘 要 随着我国经济的快速发展&#xff0c;出行选择乘坐出租车的人越来越多。与此同时电子信息技术的发展更新&#xff0c;更加准确、便捷、稳定的出租车计价收费系统随之出现。基于单片机的出租车计价系统的设计&#xff0c;不仅可以更加准确、稳定的反映计价情况&#xff0c;…

FreeRTOS—任务基础知识

文章目录 一、FreeRTOS任务特性二、FreeRTOS任务状态三、FreeRTOS任务优先级四、FreeRTOS任务实现五、任务控制块六、任务堆栈 一、FreeRTOS任务特性 简单没有使用限制&#xff08;任务数量没有显示&#xff0c;一个优先级下可以有多个任务&#xff09;支持抢占&#xff08;高…

前端谷歌浏览器调试

【浏览器调试工具精讲】Chrome Dev Tools精讲&#xff0c;前端必看&#xff01; 文章目录 命令菜单主题切换截屏窗口停放位置 常用Tabelement查找ID修改样式、样式文件定位 样式的来源如继承、自定义等让某个状态常驻如鼠标悬停全局、部分样式的的选择与取消复制样式某个样式属…

Java开发 - Canal的基本用法

前言 今天给大家带来的是Canal的基本用法&#xff0c;Canal在Java中常被我们用来做数据的同步&#xff0c;当然不是MySQL与MySQL&#xff0c;Redis与Redis之间了&#xff0c;如果是他们&#xff0c;那就好办了&#xff0c;我们可以直接通过配置来完成他们之间的主从、主主&…

【AUTOSAR】BMS开发实际项目讲解(三十)----电池管理系统电池SOH和SOE估算

电池SOH估算 关联的系统需求 Sys_Req_4004、Sys_Req_4005; 功能实现描述 SOH主要包括以下内容&#xff1a; SOH模块输入信息 序号 参数 说明 1 满电电压 4.14V 3 电芯OCV曲线 [CELL] 4 充放电循环次数 [CELL] 2 电芯循环衰减数据表 [CELL] SOH算法 ID Descr…

在docker中使用tomcat

检查本地操作系统版本&#xff1a; [rootnode ~]# cat /etc/os-release NAME"CentOS Linux" VERSION"7 (Core)" ID"centos" ID_LIKE"rhel fedora" VERSION_ID"7" PRETTY_NAME"CentOS Linux 7 (Core)" ANSI_COLO…

第8届Python编程挑战赛初赛真题剖析-2022年全国青少年信息素养大赛

[导读]&#xff1a;超平老师计划推出《全国青少年信息素养大赛Python编程真题解析》50讲&#xff0c;这是超平老师解读Python编程挑战赛系列的第1讲。 全国青少年信息素养大赛&#xff08;原全国青少年电子信息智能创新大赛&#xff09;是“世界机器人大会青少年机器人设计与信…

如何做好云渗透测试的威胁建模(上)

NO.1 威胁建模相关定义 微软针对威胁建模&#xff08;Threat modeling&#xff09;的描述&#xff1a;威胁建模是帮助保护系统、应用程序、网络和服务的有效方法。这是一种工程技术&#xff0c;用于识别潜在的威胁和建议&#xff0c;以帮助降低风险并在开发生命周期的早期实现…

nodejs接口联动获取req的各种类型数据,搭建可视化流程引擎平台

nodejs接口联动获取req的各种类型数据&#xff0c;搭建可视化流程引擎平台 搭建nodejs服务创建对外开放端口&#xff0c;获取基础数据GET—queryGET—paramsPOST 联动MYSQL数据库获取websites表的所有书链接数据库 插入 搭建nodejs服务 考虑跨域等性能&#xff0c;简易的工程化…

基于SpringBoot和Mybatis用两种方式实现分页查询

上一篇文章中封装了通用的返回结果、通用分页结果。本文具体记录一下如何基于Mybatis实现分页查询。 参考文章&#xff1a; Github:pagehelper-spring-boot Github:HowToUse.md mybatis-plus分页查询三种方法 MyBatis-Plus分页插件 系列文章指路&#x1f449; 系列文章-基于Sp…

这会是下一代的 Java 程序员的技术栈吗?

Servlet 与 Reactive 技术栈 打开 Spring 的官方文档我们在 Reactive 一栏中可以看到下面的架构图&#xff0c;其中可以很明显的看到 Reactive 的技术栈跟 Servlet 技术栈是完全并行的。意思是说我们日常开发的 Servlet web 类型只是一半的内容&#xff0c;还有另外一半世界就…

TI AM64x开发板规格书(双核ARM Cortex-A53 + 单/四核Cortex-R5F + 单核Cortex-M4F,主频1GHz)

1 评估板简介 创龙科技TL64x-EVM是一款基于TI Sitara系列AM64x双核ARM Cortex-A53 单/四核Cortex-R5F 单核Cortex-M4F多核处理器设计的高性能评估板&#xff0c;由核心板和评估底板组成。核心板经过专业的PCB Layout和高低温测试验证&#xff0c;高性能低功耗&#xff0c;稳…

3.2C++抽象类

C 抽象类 C的抽象类是指至少包含一个纯虚函数的类&#xff0c;不能被实例化。 抽象类的作用是为了实现接口的统一规范&#xff0c;使得不同的子类可以通过实现相同的纯虚函数来实现不同的行为。 定义抽象类时&#xff0c;需要在类中至少包含一个纯虚函数。 抽象类不能被实例…

idea如何连接数据库

输入数据库的用户名和密码就行 Database这里些数据库的名字 快速打开数据库设计 这句话是说时区有问题&#xff1a;因为Mysql用的是美国时区&#xff0c;要搞成中国时区&#xff1a; set global time_zone8:00; 打开cmd窗口&#xff1a; 输入 mysql -u root -p 密码&…

MySql高级篇-006 MySQL架构篇-02MySQL的数据目录:数据库下的主要目录结构、文件系统如何存储数据

第02章_MySQL的数据目录 1.MySQL8的主要目录结构 # 查询名称叫做mysql的文件目录都有哪些[rootatguigu07 ~]# find / -name mysql安装好MySQL 8之后&#xff0c;我们查看如下的目录结构&#xff1a; 1.1 数据库文件的存放路径 MySQL数据库文件的存放路径&#xff1a;/var/…

华为手环8 六月免费表盘上线,让你的腕上表盘更丰富多彩

在如今这个科技与艺术相互融合的时代&#xff01;工程师们给华为手环8花粉朋友准备的6月这一期好看又免费表盘已经上线。你可以根据自己的审美&#xff0c;选择一款最适合自己的表盘&#xff0c;展现出自己的个性和品味。快来选择你的专属表盘&#xff0c;让华为手环8成为你独特…

移动WEB开发之rem适配布局

css基础&#xff08;一&#xff09;css基础&#xff08;一&#xff09;_上半场结束&#xff0c;中场已休息&#xff0c;下半场ing的博客-CSDN博客Emmet语法Emmet语法_上半场结束&#xff0c;中场已休息&#xff0c;下半场ing的博客-CSDN博客css基础&#xff08;二&#xff09;c…

途乐证券|股市里的游资是什么?有什么特点?

股市是一个充满风险和机会的地方&#xff0c;吸引了各类投资者的目光&#xff0c;游资就是其中一种。那么股市里的游资是什么&#xff1f;有什么特点&#xff1f;途乐证券也为大家准备了相关内容&#xff0c;以供参考。 股市里的游资是什么&#xff1f; 一般来说&#xff0c;股…

【JavaScript】使用qrcode生成二维码

QRCode简介&#xff1a; QRCode.js 是一个用于生成二维码的 JavaScript 库。主要是通过获取 DOM 的标签,再通过 HTML5 Canvas 绘制而成,不依赖任何库。 使用步骤&#xff1a; 点击下载&#xff1a;https://github.com/davidshimjs/qrcodejs 或者mirrors / davidshimjs / qrco…