【C++干货基地】特殊函数名的函数:赋值运算符重载


在这里插入图片描述

🎬 鸽芷咕:个人主页

 🔥 个人专栏: 《C++干货基地》《粉丝福利》

⛺️生活的理想,就是为了理想的生活!

引入

  哈喽各位铁汁们好啊,我是博主鸽芷咕《C++干货基地》是由我的襄阳家乡零食基地有感而发,不知道各位的城市有没有这种实惠又全面的零食基地呢?C++ 本身作为一门篇底层的一种语言,世面的免费课程大多都没有教明白。所以本篇专栏的内容全是干货让大家从底层了解C++,把更多的知识由抽象到简单通俗易懂。

⛳️ 推荐

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。

文章目录

  • 引入
  • ⛳️ 推荐
  • 一、运算符重载
    • 1.1 == 运算符重载
    • 1.2 < 运算符重载
  • 二、赋值运算符重载
    • 2.1 赋值运算符重载格式
    • 2.2 赋值运算符重载的行为
    • 2.4 有了自动生成的赋值重载我们还需要自己写吗?
  • 三、前置++ 和 后置++
  • 四、模拟日期类的所有运算重载
    • + 和 += 减 和 减等
    • == 和 != and < 和 <= > 和 >=

一、运算符重载

C++ 中为了增加代码的可读性运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

函数名字为:关键字operator后面接需要重载的运算符符号。

函数原型:返回值类型 operator操作符(参数列表)

🔥 注意:

  • 不能通过连接其他符号来创建新的操作符:比如operator@
  • 重载操作符必须有一个类类型参数
  • 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
  • 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
  • .* :: sizeof ? : . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。**

1.1 == 运算符重载

下面我们就来实践一下再日期类中 == 运算符如何重载, 以往我们在 内置类型 == 运算符返回的都是bool 类型

  • 这样的话返回类型就确定了
  • 运算符重载 的关键字是 operator
  • 函数原型:返回值类型 operator操作符(参数列表)

🍸 代码演示:

class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}bool operator==(const Date& d1){return _year == d1._year&& _month == d1._month&& _day == d1._day;}private:int _year;int _month;int _day;
};int main()
{Date d1(2022, 1, 13);Date d2(2022, 1, 14);Date d3(2022, 1, 13);cout << (d1 == d2) << endl;cout << (d1 == d3) << endl;return 0;
}

在这里插入图片描述

1.2 < 运算符重载

< 运算符重载就更加简单了,和 运算符 == 的规则一样只需要改变一下我们类成员的比较方法就可以了

🍸 代码演示:

class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}bool operator==(const Date& d1){return _year == d1._year&& _month == d1._month&& _day == d1._day;}bool operator< (const Date& d1){if (_year < d1._year){return true;}else if (_year == d1._year){if (_month < d1._month){return true;}else{return _day < d1._day;}}return false;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2022, 1, 13);Date d2(2022, 1, 14);Date d3(2022, 1, 13);cout << (d1 < d2) << endl;cout << (d1 < d3) << endl;return 0;
}

二、赋值运算符重载

前面的几个赋值运算符重载比较简单,只是为了完成类是如何比较的而赋值运算符就是我们这里比较关键的了

  • 赋值运算符重载 主要是赋值,把一个对象赋值给另一个对象
  • 拷贝构造函数 主要是,同类型的对象创建初始化时调用

2.1 赋值运算符重载格式

  • 参数类型:const T&,传递引用可以提高传参效率
  • 返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
  • 检测是否自己给自己赋值
  • 返回*this :要复合连续赋值的含义

这里我们为什么要讲返回值类型设定为 & 引用类型呢?赋值运算不就简单赋值就好了:

  • 那么我们就来看一下下面这段代码

class Date
{
public:Date(int year=2022, int month=10, int day=21){_year = year;_month = month;_day = day;}bool operator==(const Date& d1){return _year == d1._year&& _month == d1._month&& _day == d1._day;}bool operator< (const Date& d1){if (_year < d1._year){return true;}else if (_year == d1._year){if (_month < d1._month){return true;}else{return _day < d1._day;}}return false;}bool operator!=(const Date& d){return ~(*this == d);}void operator=(const Date& d){_year = d._year;_month = d._year;_day = d._day;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2022, 1, 13);Date d2;Date d3;d2 = d3 = d1;int a, b;a = b = 10;return 0;
}

在这里插入图片描述

这里为什么内置类型可以连续赋值而自定类型不可以?内置类型我们都知道是从后往前连续赋值的

  • 也就是 10 先赋值给 b 然后 b 在赋值给 a,而我们并没有给赋值运算符重载返回一个值所以
  • 就提示我们 二元 “=” 运算符没有找到与它匹配的操作数

所以我们的返回值就必须是this 指针所指向的内容代码改进如下:

class Date
{
public:Date(int year=2022, int month=10, int day=21){_year = year;_month = month;_day = day;}bool operator==(const Date& d1){return _year == d1._year&& _month == d1._month&& _day == d1._day;}bool operator< (const Date& d1){if (_year < d1._year){return true;}else if (_year == d1._year){if (_month < d1._month){return true;}else{return _day < d1._day;}}return false;}bool operator!=(const Date& d){return ~(*this == d);}Date& operator=(const Date& d){if (*this != d){_year = d._year;_month = d._year;_day = d._day;}return *this;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2022, 1, 13);Date d2;Date d3;d2 = d3 = d1;return 0;
}

多加了一个 if 判断是为了避免 d1 = d1; 这样的写法去又重新赋值一遍

2.2 赋值运算符重载的行为

在这里插入图片描述

赋值运算符重载既然也是六大默认成员函数之一那么肯定也是我们不写自动生成一个默认的复制运算符重载 ,那么究竟有什么行为呢?

构造函数和析构函数他们的行为都是对内置类型不处理对自动定义类型调用他们的析构或者构造函数,而 赋值运算符重载是和 拷贝构造一样的行为,我们不写会自定生成一个默认函数,默认的赋值运算符重载 以值的方式逐字节拷贝。

  • 🔥 注:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。

2.4 有了自动生成的赋值重载我们还需要自己写吗?

答案是肯定的,自动生成的 默认赋值重载 只会完成浅拷贝,也就是值拷贝当遇到需要申请资源的类时 就会出现问题!

  • 默认生成的赋值重载只完成值拷贝会把俩个指针的指向都改为同一个方向就会导致程序崩溃
typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 10){_array = (DataType*)malloc(capacity * sizeof(DataType));if (nullptr == _array){perror("malloc申请空间失败");return;}_size = 0;_capacity = capacity;}void Push(const DataType& data){// CheckCapacity();_array[_size] = data;_size++;}~Stack(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}
private:DataType* _array;size_t _size;size_t _capacity;
};
int main()
{Stack s1;s1.Push(1);s1.Push(2);s1.Push(3);s1.Push(4);Stack s2;s2 = s1;return 0;
}

在这里插入图片描述

这里s2 的指针被 s1 所指向的地址给以值的方式赋值了,所以 s2 s1 指向的是同一块空间当他们自动调用析构函数时就会对同一块地址释放俩次导致程序崩溃

三、前置++ 和 后置++

前面我们重载的都是二元的运算符,看似只有一个显示定义的参数其实还有一个this指针

  • 例如d1 == d2 虽然我们是这样写的但是会转换为
  • d1.operator==(d2) 这样的,那前置 ++ 和后置++ 都是一元操作符且运算符都是一样的如何进行重载呢?

下面我们就来尝试重载一下前置++,前置++ 我相信大家都用过返回的是++之后的值

🍸 代码演示:

	Date& operator++(){_day++;return *this;}

而我们的后置++ 返回的是++之前的值先使用在++所以需要返回+1之前的旧值,故需在实现时需要先将this保存一份,然后给this+1

后置++:

  • 前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载
  • C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器自动传递
Date operator++(int){Date tmp(*this);_day += 1;return tmp;}

四、模拟日期类的所有运算重载

+ 和 += 减 和 减等

== 和 != and < 和 <= > 和 >=

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OceanBase生产环境安装部署的最优实践

关于生产环境&#xff0c;为了尽量确保性能和稳定性&#xff0c;我们比较建议采用标准化的配置进行部署&#xff0c;例如接下来会提到的服务初始化、日志管理和数据分盘等关键步骤。而在非生产环境中&#xff0c;如果条件满足&#xff0c;同样建议遵循规范部署的原则。 前期准备…

SpringBoot如何写好单元测试

&#x1f413;序言 Spring中的单元测试非常方便&#xff0c;可以很方便地对Spring Bean进行测试&#xff0c;包括Controller、Service和Repository等Spring Bean进行测试&#xff0c;确保它们的功能正常&#xff0c;并且不会因为应用的其他变化而出现问题。 &#x1f413;单元测…

CSS问题精粹1

1.关于消除<li>列表前的符号 我相信很多人在初学CSS时会遇到该问题&#xff0c;无论是创作导航&#xff0c;还是列表&#xff0c;前面都会有个黑点点或其它符号。 解决该问题其实很简单 采用list-style-type:none或list-style:none直接解决 如果你想更换前面的黑点点&a…

进程的概念 | PCB | Linux下的task_struct | 父子进程和子进程

在讲进程之前首先就是需要去回顾一下我们之前学的操作系统是干嘛的&#xff0c;首先操作系统是一个软件&#xff0c;它是对上提供一个良好高效&#xff0c;稳定的环境的&#xff0c;这是相对于用户来说的&#xff0c;对下是为了进行更好的软硬件管理的&#xff0c;所以操作系统…

MySQL之索引与事务

一 索引的概念 一种帮助系统查找信息的数据 数据库索引 是一个排序的列表&#xff0c;存储着索引值和这个值所对应的物理地址无须对整个表进行扫描&#xff0c;通过物理地 址就可以找到所需数据是表中一列或者若干列值排序的方法 需要额外的磁盘空间 索引的作用 1 数据库…

浅谈RPC的理解

浅谈RPC的理解 前言RPC体系Dubbo架构最后 前言 本文中部分知识涉及Dubbo&#xff0c;需要对Dubbo有一定的理解&#xff0c;且对源码有一定了解 如果不了解&#xff0c;可以参考学习我之前的文章&#xff1a; 浅谈Spring整合Dubbo源码&#xff08;Service和Reference注解部分&am…

数字化战略失配企业现状,可惜了!

尽管大部分的企业领导者已经意识到数字化转型对于企业革新业务模式、提升运营效率、抢占市场先机的关键作用&#xff0c;但是&#xff0c;认知上的转变并不等同于成功的实践。在实际操作中&#xff0c;往往出现战略与企业现状不符的现象&#xff0c;这无疑会使得所有的努力付诸…

windows查看局域网内所有已使用的IP IP扫描工具 扫描网段下所有的IP Windows环境下

推荐使用&#xff1a; Advanced IP Scanner 官网下载&#xff1a; https://www.advanced-ip-scanner.com/

学习vue3第九节(新加指令 v-pre/v-once/v-memo/v-cloak )

1、v-pre 作用&#xff1a;防止编译器解析某个特定的元素及其内容&#xff0c;即v-pre 会跳过当前元素以及其子元素的vue语法解析&#xff0c;并将其保持原样输出&#xff1b; 用于&#xff1a;vue 中一些没有指令和插值表达式的节点的元素&#xff0c;使用 v-pre 可以提高 Vu…

LeetCode 17 / 100

目录 普通数组最大子数组和合并区间轮转数组除自身以外数组的乘积缺失的第一个正数 LeetCode 53. 最大子数组和 LeetCode 56. 合并区间 LeetCode 189. 轮转数组 LeetCode 238. 除自身以外数组的乘积 LeetCode 41. 缺失的第一个正数 普通数组 最大子数组和 给你一个整数数组 …

十、MySQL主从架构配置

目录 一、资源配置 二、主从同步基本原理&#xff1a; 1、具体步骤&#xff1a; 2、数据库是靠什么同步的&#xff1f; 3、pos与GTID的区别&#xff1f; 三、配置一主两从 &#xff08;1&#xff09;为主库和从库创建复制账户&#xff0c; 分别在主从库上执行如下命令&a…

React Native:跨平台移动应用开发的利器

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Python进程与线程开发

目录 multiprocessing模块 线程的开发 threading模块 setDaemon 死锁 线程间的通信 multiprocessing模块 运行python的时候&#xff0c;我们都是在创建并运行一个进程&#xff0c;(linux中一个进程可以fork一个子进程&#xff0c;并让这个子进程exec另外一个程序)。在pyt…

机器学习——压缩网络作业

文章目录 任务描述介绍知识蒸馏网络设计 Baseline实践 任务描述 网络压缩&#xff1a;使用小模型模拟大模型的预测/准确性。在这个任务中&#xff0c;需要训练一个非常小的模型来完成HW3&#xff0c;即在food-11数据集上进行分类。 介绍 有许多种网络/模型压缩的类型&#xff0…

Java并发

目录 线程 什么是线程 进程和线程的区别 线程的生命周期 什么是多线程 并发与并行 多线程的三种实现方式 继承Thread类 1.创建类继承Thread类 2.重写run&#xff08;&#xff09;方法 3.创建对象启动线程 实现Runnable接口 1.自己定义一个类实现Runnable接口 2.重…

由浅到深认识C语言(14):枚举

该文章Github地址&#xff1a;https://github.com/AntonyCheng/c-notes 在此介绍一下作者开源的SpringBoot项目初始化模板&#xff08;Github仓库地址&#xff1a;https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址&#xff1a;https://blog.csdn…

python毕业设计基于flask应急救援调度系统django

此系统设计主要采用的是python语言来进行开发&#xff0c;采用flask框架技术&#xff0c;框架分为三层&#xff0c;分别是控制层Controller&#xff0c;业务处理层Service&#xff0c;持久层dao&#xff0c;能够采用多层次管理开发&#xff0c;对于各个模块设计制作有一定的安全…

动态规划题目练习

基础知识&#xff1a; 动态规划背包问题-CSDN博客 动态规划基础概念-CSDN博客 题目练习&#xff1a; 题目1&#xff1a;过河卒 题目描述 棋盘上 A 点有一个过河卒&#xff0c;需要走到目标 B 点。卒行走的规则&#xff1a;可以向下、或者向右。同时在棋盘上 C 点有一个对方的马…

WebGIS管线在线编辑器(电力、水力、燃气、热力、热能管线)

随着GIS等信息技术的发展&#xff0c;地下管线管理也从二维平面向三维立体管理迈进。传统管线信息管理系统将管线及其附属设施抽象成二维平面内的点、要素&#xff0c;并使用各类点符号、不同颜色线段进行表达。虽能一定程度上满足城市智慧运行的需要&#xff0c;但不能很直观的…

【Linux】文件描述符 - fd

文章目录 1. open 接口介绍1.1 代码演示1.2 open 函数返回值 2. 文件描述符 fd2.1 0 / 1 / 22.2 文件描述符的分配规则 3. 重定向3.1 dup2 系统调用函数 4. FILE 与 缓冲区 1. open 接口介绍 使用 man open 指令查看手册&#xff1a; #include <sys/types.h> #include …