c++编程(6)——类与对象(4)运算符重载、赋值重载函数

欢迎来到博主的专栏——C++编程
博主ID:代码小豪

文章目录

    • 运算符重载
    • 赋值重载函数
    • 默认赋值重载函数
    • 其他运算符重载函数

运算符重载

重载这个概念在c++中已经出现两次了,在前面的文章中,函数重载指的是可以用相同名字的函数实现不同的功能。而运算符重载则是可以用相同的运算符实现不同的功能。

运算符也能重载吗?在C语言也有可以复用的运算符,在不同的运用场景下有不同的作用,比如乘法操作符(*)和解引用操作符(*),取地址操作符(&)和位运算操作符(&)。

但这些和c++的运算符重载可不一样。在c++语言中,可以用operator加上运算符来表示函数,叫做运算符重载。运算符重载的声明格式如下:

返回类型 operator 运算符(参数列表……);

运算符是一种特殊形式的函数,即将运算符重载成一个与原运算符符号一致,但是重载运算符是一个函数,而原操作符是一个操作符,这个操作符就成为了一个可以调用的函数名。

其实大家在初学c++的时候就已经见过重载的运算符了。

	cout << “hello world” << endl;

这个和左移操作符一样的就是重载操作符,其函数原型可以在c++参考手册中可以看到。

c++参考手册网址:cplusplus

ostream& operator<< (bool val);ostream& operator<< (short val);ostream& operator<< (unsigned short val);ostream& operator<< (int val);ostream& operator<< (unsigned int val);ostream& operator<< (long val);ostream& operator<< (unsigned long val);ostream& operator<< (float val);ostream& operator<< (double val);ostream& operator<< (long double val);ostream& operator<< (void* val);
	
ostream& operator<< (streambuf* sb );
	
ostream& operator<< (ostream& (*pf)(ostream&));ostream& operator<< (ios& (*pf)(ios&));ostream& operator<< (ios_base& (*pf)(ios_base&));

赋值重载函数

我们还是再拿date类型举例:

class Date
{
public:
	Date(int year = 2024, int month = 4, int day = 16);//默认构造函数
	Date(const Date& d);//拷贝构造函数

	Date& operator =(const Date& D1);//赋值重载函数
private:
	int _year;
	int _month;
	int _day;
};
Date::Date(int year, int month, int day)//默认构造函数
{
	_year = year;
	_month = month;
	_day = day;
}

Date::Date(const Date& d)//拷贝构造函数
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}

内置类型的赋值操作符是(=)。赋值重载函数可以让自定义类型的变量用(=)实现赋值操作。首先要让赋值操作符重载成函数。Date类的复制操作函数的声明如下:

Date& operator =(const Date& D1);//赋值重载函数


既然函数是要实现赋值操作,那么函数的定义内容就是要让Date类的变量进行拷贝。

Date& Date::operator=(const Date& d1)
{
	if (this != &d1)//若是参数是对象本身,那么就不需要将成员一一拷贝,无意义且浪费时间
	{
		_year = d1._year;
		_month = d1._month;
		_day = d1._day;
	}
	return (*this);
}

参数类型使用const Date&,传递引用可以提高效率
返回类型使用const Date&,提高效率
检测是否为自己赋值,提高效率
返回*this可以让对象实现连续赋值

调用复制重载函数有两种方式,一种是和函数一样传递参数。

	Date d1;
	Date d2;
	Date d3;
	d1.operator=(d2);
	d1.operator=(d2).operator=(d3);
	

也可以用运算符的形式调用函数,运算符与调用时的不同之处在于:对于普通函数,实参出现在函数的括号内,而操作符调用,实参出现在操作符两侧:

	d1 = d2;
	d1 = d2 = d3;

当运算符重载在类中时,函数显示的调用实参只有一个,但是实际上参与函数的实参有两个,一个是指向对象的this指针(this指针在上一篇文章中讲过),另外一个是被显示调用的实参。

在上例中,调用函数的对象是d1,因此this指针指向d1,将this解引用(*this)后得到的是d1,实参传递的是d2.

重载的赋值运算符是一个二元操作符,因此实际调用的参数必须是两个,比如将复制重载函数的声明修改成下例,那么编译器会报错。

Date& operator =(const Date& D1,Date&D2);

在这里插入图片描述
这是因为这个赋值重载函数是声明在类中的,类的this指针占据的一个参数,D1和D2作为实际上传的参数有两个,那么这个赋值重载函数的的参数共计三个。赋值操作符(=)如果是一个三元操作符,那么肯定是不符合逻辑的,因而不能超过操作符的操作数。

定义在全局(类外)的赋值重载函数的参数列表就可以声明两个形式参数。

Date& Date::operator =(Date& D1, Date& d2);//赋值重载函数

定义在类外的函数没有this指针指向对象,因此可以定义两个参数。

默认赋值重载函数

我们将Date类的赋值重载函数的声明和定义注释掉,运行以下代码:

    Date d1;
	Date d2;
	Date d3;
	d1 = d2;
	d1 = d2 = d3;

通过调试,可以发现这段代码的编译过了,而且也实现的拷贝的功能
在这里插入图片描述
明明没有定义复制重载函数,怎么还能实现这些操作呢?这是因为若是用户没有实现赋值重载函数,编译器会生成一个默认的赋值重载函数,这个默认赋值重载函数是以值拷贝的形式实现的。和默认拷贝构造函数的作用类似。内置类型的成员变量直接赋值,自定义类型的成员变量则调用该类的赋值重载函数。

其他运算符重载函数

其他的运算符重载函数就没有赋值运算符重载那么重要了(毕竟赋值运算符有默认的函数生成,而其他的没有,除了取地址重载(&))。不能重载的运算符有(.*)(::)(sizeof)(.)(?:)。

具体要重载什么运算符,需要看这个类要实现什么功能,以Date类为例,我们可以实现判断的运算符(==,>,<等)。

    bool operator==(const Date& D1)const;
    
    bool operator>(const Date& D1)const;

	bool operator!=(const Date& D1)const;

	bool operator>=(const Date& D1)const;
	
	bool operator<(const Date& D1)const;

在类中声明以上函数。

(==)需要判断两个对象是否相同,我们思考一下日期如何才算是相同?相同的日期需要具有以下特点:
年相等
月相等
日相等。

根据这个逻辑得到下面的函数定义:

bool Date::operator==(const Date& d1)const
{
	return _year == d1._year &&
		_month == d1._month &&
		_day == d1._day;
}

运算符重载函数并不需要将所有的内容都实现出来,有时候可以复用其他的重载函数,前提是符合这个运算符的逻辑

例如不等(!=)运算符,其逻辑是与(==)相反的,因此可以复用==运算符重载函数实现。

bool Date::operator!=(const Date& D1)const
{
	return !(*this == D1);
}

\(>)大于重载运算符的逻辑应该如下:
比较的日期的年份,大于则返回ture。
若年份相等,比较月份,大于则返回true
若月份相等,比较天数,大于则返回true
其余情况(包括日期相等)都返回false。

bool Date::operator>(const Date& D1)const
{
	if (_year > D1._year)
	{
		return true;
	}
	else if (_year == D1._year)
	{
		if (_month > D1._month)
		{
			return true;
		}
		else if (_month == D1._month)
		{
			if (_day > D1._day)
			{
				return true;
			}
		}
	}

	return false;
}

接着实现>=和<,这些运算符的逻辑都是能和>和==运算符复用的。实现如下:

bool Date::operator>=(const Date& D1)const
{
	return (*this) == D1 || (*this) > D1;
}

bool Date::operator<(const Date& D1)const
{
	return !(*this >= D1);
}

为什么运算符重载函数需要符合运算符的逻辑呢?大家可以试一下,比如讲大于的逻辑写成小于,或者其他功能。这个函数是能通过编译的,但是这么做有什么好处呢?当然是什么都没有。我们可以涉想这么一个场景。你是某个公司的程序员,你从别人那里调用了一个库,这个库将某个类的加法运算符的逻辑写成了减法。并且导致了你的程序不停的出错花费了大量时间调试和修改,最后发现是同事的恶作剧,那么请问你什么感受呢?因此运算符重载函数的逻辑应该与运算符的本身逻辑一致。大大的增加了程序的可读性。这样才是c++推出运算符重载的初衷。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【WebSocket连接异常】前端使用WebSocket子协议传递token时,Java后端的正确打开方式!!!

文章目录 1. 背景2. 代码实现和异常发现3. 解决异常3.1 从 URL入手3.2 从 WebSocket子协议的使用方式入手&#xff08;真正原因&#xff09; 4. 总结&#xff08;仍然存在的问题&#xff09; 前言&#xff1a; 本篇文章记录的是使用WebSocket进行双向通信时踩过的坑&#xff0c…

将gdip-yolo集成到yolov9模型项目中(支持预训练的yolov9模型)

1、yolov9模型概述 1.1 yolov9 YOLOv9意味着实时目标检测的重大进步&#xff0c;引入了可编程梯度信息&#xff08;PGI&#xff09;和通用高效层聚合网络&#xff08;GELAN&#xff09;等开创性技术。该模型在效率、准确性和适应性方面取得了显著改进&#xff0c;在MS COCO数…

「 安全工具介绍 」软件成分分析工具Black Duck,业界排名TOP 1的SCA工具

在现代的 DevOps 或 DevSecOps 环境中&#xff0c;SCA 激发了“左移”范式的采用。提早进行持续的 SCA 测试&#xff0c;使开发人员和安全团队能够在不影响安全性和质量的情况下提高生产力。前期在博文《「 网络安全常用术语解读 」软件成分分析SCA详解&#xff1a;从发展背景到…

Qt-饼图示范

1.效果图 2.代码如下 2.1 .h文件 #ifndef PIECHARTWIDGET_H #define PIECHARTWIDGET_H#include <QWidget> #include <QChartView> #include <QPieSeries>#include<QVBoxLayout> #include<QMessageBox> #include <QtCharts>struct PieDat…

FastAPI - uvicorn设置 logger 日志格式

怎么将日志打印到文件 在main.py加入log_config“./uvicorn_config.json” import uvicornif __name__ "__main__":uvicorn.run("app:app", host"0.0.0.0", port8000, log_config"./uvicorn_config.json")uvicorn_config.json {&qu…

“互联网+”创意创业大赛活动方案

大赛历时6个月&#xff0c;总体分两个赛程&#xff1a;一是策划创意阶段。评审的是方案。二是组织实施阶段。通过阶段一立项的项目由公司协助实施&#xff0c;最终评审的是项目落实情况。学生可两个赛程单独参加&#xff0c;也可连续参加。 具体流程及时间安排如下&#xff1a;…

ansible-tower连接git实现简单执行playbook

前提&#xff1a;安装好ansible-tower和git&#xff0c;其中git存放ansible得剧本 其中git中得内容为&#xff1a; --- - name: yjxtesthosts: yinremote_user: rootgather_facts: noroles:- testroles/test/tasks/main.yml #文件内容 --- #- name: Perform Test Task # tas…

单链表-通讯录

目录 单链表实现 通讯录代码实现 初始化 初始化函数 添加 删除 展示 查找 修改 销毁 代码展示 main.c text.c text.h list.c list.h 和前面的通讯录实现差不多这次就是实现一个以单链表为底层的通讯录 单链表实现 数据结构&#xff1a;单链表-CSDN博客 通讯…

OpenHarmony多媒体-video_trimmer

简介 videotrimmer是在OpenHarmony环境下&#xff0c;提供视频剪辑能力的三方库。 效果展示&#xff1a; 安装教程 ohpm install ohos/videotrimmerOpenHarmony ohpm环境配置等更多内容&#xff0c;请参考 如何安装OpenHarmony ohpm包 。 使用说明 目前支持MP4格式。 视频…

docker部署的nginx配置ssl证书https

申请ssl证书&#xff0c;已腾讯的免费证书为例 2.上传证书到linux服务器 2.1 映射ssql目录 首先确保容器命令已映射宿主机目录&#xff0c;不一定是ssl&#xff0c;也可以是其他路径。 2.2 上传文件到指定路径 以我映射的ssl路径为例&#xff0c;我上传到宿主机的 /usr/local…

【GEE实践应用】使用MODIS NDVI数据集绘制研究区域每日NDVI序列曲线

// 设置研究区域 var geometry table;// 选择MODIS NDVI 数据集 var modisNDVI ee.ImageCollection(MODIS/006/MOD13A2).filterBounds(geometry).filterDate(2000-01-01, 2023-12-31);// 计算每天的平均 NDVI var dailyMeanNDVI modisNDVI.map(function(image) {var date e…

(最详细)关于List和Set的区别与应用

关于List与Set的区别 List和Set都继承自Collection接口&#xff1b; List接口的实现类有三个&#xff1a;LinkedList、ArrayList、Vector。Set接口的实现类有两个&#xff1a;HashSet(底层由HashMap实现)、LinkedHashSet。 在List中&#xff0c;List.add()是基于数组的形式来添…

OpenHarmony网络组件-Mars

项目简介 Mars 是一个跨平台的网络组件&#xff0c;包括主要用于网络请求中的长连接&#xff0c;短连接&#xff0c;是基于 socket 层的解决方案&#xff0c;在网络调优方面有更好的可控性&#xff0c;暂不支持HTTP协议。 Mars 极大的方便了开发者的开发效率。 效果演示 编译…

简述Kafka的高可靠性

什么叫可靠性&#xff1f; 大家都知道&#xff0c;系统架构有三高&#xff1a;「高性能、高并发和高可用」&#xff0c;三者的重要性不言而喻。 对于任意系统&#xff0c;想要同时满足三高都是一件非常困难的事情&#xff0c;大型业务系统或者传统中间件都会搭建复杂的架构来…

万字长文带你APK反编译重签名aabapks转换

Android反编译 反编译&#xff08;Decompilation&#xff09;是将已编译的程序&#xff08;比如二进制代码&#xff09;转换回更高级别的编程语言代码的过程。这通常用于理解程序的工作原理&#xff0c;进行软件审计&#xff0c;恢复丢失的源代码&#xff0c;或者进行教学研究…

提升数据质量的三大要素:清洗prompt、数据溯源、数据增强(含Reviewer2和PeerRead)​

前言 我带队的整个大模型项目团队超过40人了&#xff0c;分六个项目组 每个项目组都是全职带兼职&#xff0c;且都会每周确定任务/目标/计划然后各项目组各自做任务拆解&#xff0c;有时同组内任务多时 则2-4人一组 方便并行和讨论&#xff0c;每周文档记录当周工作内容&…

Leetcode 4.18

Leetcode 1.无重复字符的最长子串2.最长回文子串3.整数反转4.字符串转换整数 (atoi)5.正则表达式匹配 1.无重复字符的最长子串 无重复字符的最长子串 滑动窗口&#xff0c;先让右指针右移&#xff0c;如果发现这个子串有元素和右指针当前元素重复。 则&#xff1a; 左指针右移…

HackmyVM-----Boxing靶机

文章目录 正常打靶流程1.获取靶机IP地址2.获取靶机端口服务3.访问网页4.添加域名WindowsLinux 5.访问域名6.nc反弹shell 7.结束 正常打靶流程 1.获取靶机IP地址 ┌──(root㉿kali)-[/home/kali] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:10:3c:9b, …

Stable Diffusion XL优化终极指南

如何在自己的显卡上获得SDXL的最佳质量和性能&#xff0c;以及如何选择适当的优化方法和工具&#xff0c;这一让GenAI用户倍感困惑的问题&#xff0c;业内一直没有一份清晰而详尽的评测报告可供参考。直到全栈开发者Flix San出手。 在本文中&#xff0c;Flix介绍了相关SDXL优化…

H264标准协议基础3

参考博文 上一篇H264标准协议基础2 1.解码视频帧的poc计算 2.残差4x4 矩阵中的trailingones & numcoeff 2.1查表 trailingones 表达出尾部one(1,-1)系数的个数,按照zigzag扫描出(1,-1)个数,trailingones的最大为3; numcoeff 表达非零值系数的个数,最多为16个…