当前位置: 首页 > news >正文

【C++ | 拷贝赋值运算符函数】一文了解C++的 拷贝赋值运算符函数

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
⏰发布时间⏰:2024-06-09 16:06:48

本文未经允许,不得转发!!!

目录

  • 🎄一、为什么需要 赋值运算符函数
  • 🎄二、什么是 赋值运算符函数
  • 🎄三、使用 赋值运算符函数
  • 🎄四、默认的 赋值运算符函数
  • 🎄五、总结



在这里插入图片描述

🎄一、为什么需要 赋值运算符函数

如果使用一个同类型对象给当前对象赋值,会调用这个类的赋值运算符函数,而默认的赋值运算符函数只进行浅拷贝,可能无法满足一些类的需求,所以需要自定义赋值运算符函数。

下面例子,演示默认的赋值运算符函数存在的问题:

// g++ 12_Operator=_Date.cpp
#include <iostream>
#include <stdio.h>using namespace std;class CDate
{
public:CDate(){}							// 无参构造CDate(int year, int mon, int day);	// 构造函数声明CDate(const CDate& date);			// 拷贝构造函数声明~CDate();							// 析构函数声明void show(){//cout << "Date: " << m_year << "." << m_mon << "." << m_day << endl;cout << "Date: " << str << endl;}private:int m_year;int m_mon;int m_day;char *str;
};// 构造函数定义
CDate::CDate(int year, int mon, int day)
{m_year = year;m_mon = mon;m_day = day;str = new char[64];sprintf(str, "%4d.%02d.%02d", year,mon,day);cout << "Calling Constructor" << ", this=" << this <<endl;
}// 拷贝构造函数定义
CDate::CDate(const CDate& date)
{m_year = date.m_year;m_mon = date.m_mon;m_day = date.m_day;str = new char[64];sprintf(str, "%4d.%02d.%02d", m_year,m_mon,m_day);cout << "Calling Copy Constructor" << ", this=" << this <<endl;
}// 析构函数定义
CDate::~CDate()
{cout << "Calling Destructor" << ", this=" << this <<endl;delete [] str;
}int main()
{CDate date_1(2024,06,05);CDate date_2;date_2=date_1;	// 调用默认赋值运算符 2024-06-09 13:39:05return 0;
}

运行结果,因为默认赋值运算符只进行浅拷贝,直接复制了date_1的str指针的值,但是两个对象销毁时,却delete了两次str,导致double free
在这里插入图片描述
清楚问题之后,我们学习一下怎样声明、定义自己的拷贝赋值运算符函数来规避这个问题。


在这里插入图片描述

🎄二、什么是 赋值运算符函数

赋值运算符函数 是重载运算符的一种,关于重载运算符,后面会用其他文章来解释,总之赋值运算符函数的本质也是类成员函数。关于 赋值运算符函数,我们需要了解它是什么时候调用的,其函数原型是怎样的,怎样声明、定义自己的赋值运算符函数。

ANSI C 允许结构赋值, 而 C++允许类对象赋值, 这是通过自动为类重载赋值运算符实现的。这种运算符的原型如下:

类类型 & 类名:operator=(const 类类型 &);
CDate & CDate:operator=(const CDate &); // CDate 类的赋值运算符

怎样声明、定义自己的赋值运算符函数,有下面几个注意点:
1、赋值运算符函数的名称是operator=,其中operator是C++的关键字,专门用于重载运算符。
2、赋值运算符函数只允许一个参数,且是该类对象的引用,const表示不会修改该对象的内容。
3、赋值运算符函数返回值类型是该类对象的引用,一般不使用const修饰,这样可以支持连续赋值date1=date2=date3
4、赋值运算符函数在实现时应当避免将对象赋给自身,可以判断对象地址来实现this==&date
5、如果存在new分配的内容,需要先释放旧的内存

下面以CDate为例,演示声明、定义自己的 赋值运算符函数:

// 在类中声明,下面隐藏了类的其他代码
class CDate
{
public:...CDate& operator=(const CDate& date);// 赋值运算符函数声明...
};// 赋值运算符函数定义
CDate& CDate::operator=(const CDate& date)
{if(this == &date)	// 赋值给自身return *this;delete [] str;		// 释放旧的数据m_year = date.m_year;m_mon = date.m_mon;m_day = date.m_day;str = new char[64];sprintf(str, "%4d.%02d.%02d", m_year,m_mon,m_day);cout << "Calling operator=" << ", this=" << this <<endl;return *this;
}

在这里插入图片描述

🎄三、使用 赋值运算符函数

知道了怎样声明、定义自己的赋值运算符函数后。这一小节,了解何时使用 赋值运算符函数。

将已有的对象赋值给另一个对象时,就会调用 赋值运算符函数。而使用赋值号(=)给对象初始化时则可能调用拷贝构造函数。

这里有两种情况,一种是赋值(对象之前就定义好了),一种是初始化(正在定义某个对象,对象前带有类型)。
下面是a赋值给b:

int a=0;
int b;
b = a; 	// a赋值给b

下面是使用a的值给b初始化:

int a=0;
int b=a;	// 用a的值给b初始化

下面代码演示了怎么声明、定义、使用赋值运算符函数:

// g++ 12_Operator=_Date.cpp
#include <iostream>
#include <stdio.h>using namespace std;class CDate
{
public:CDate()								// 无参构造{m_year = m_mon = m_day = 0;str = NULL;}							CDate(int year, int mon, int day);	// 构造函数声明CDate(const CDate& date);			// 拷贝构造函数声明~CDate();							// 析构函数声明CDate& operator=(const CDate& date);// 赋值运算符函数声明void show(){//cout << "Date: " << m_year << "." << m_mon << "." << m_day << endl;cout << "Date: " << str << endl;}private:int m_year;int m_mon;int m_day;char *str;
};// 构造函数定义
CDate::CDate(int year, int mon, int day)
{m_year = year;m_mon = mon;m_day = day;str = new char[64];sprintf(str, "%4d.%02d.%02d", year,mon,day);cout << "Calling Constructor" << ", this=" << this <<endl;
}// 拷贝构造函数定义
CDate::CDate(const CDate& date)
{m_year = date.m_year;m_mon = date.m_mon;m_day = date.m_day;str = new char[64];sprintf(str, "%4d.%02d.%02d", m_year,m_mon,m_day);cout << "Calling Copy Constructor" << ", this=" << this <<endl;
}// 析构函数定义
CDate::~CDate()
{cout << "Calling Destructor" << ", this=" << this <<endl;delete [] str;
}// 赋值运算符函数定义
CDate& CDate::operator=(const CDate& date)
{if(this == &date)	// 赋值给自身return *this;delete [] str;		// 释放旧的数据m_year = date.m_year;m_mon = date.m_mon;m_day = date.m_day;str = new char[64];sprintf(str, "%4d.%02d.%02d", m_year,m_mon,m_day);cout << "Calling operator=" << ", this=" << this <<endl;return *this;
}int main()
{CDate date_1(2024,06,05);CDate date_2, date_3;date_3 = date_2=date_1;	// 调用赋值运算符函数 2024-06-09 15:00:36return 0;
}

运行结果如下:
在这里插入图片描述


在这里插入图片描述

🎄四、默认的 赋值运算符函数

与处理拷贝构造函数一样,如果一个类末定义自己的拷贝赋值运算符函数,编译器会为它生成一个合成拷贝赋值运算符(synthesized copy-assignment operator)。

合成的拷贝构造函数会逐个复制非静态成员( 成员复制也称为浅复制)的值到目标对象中。根据成员类型有下面几种情况:
1、如果成员是内置类型,则直接复制;
2、如果成员本身就是类对象,则将使用这个类的拷贝构造函数来复制类对象;
3、如果成员是数组,默认的拷贝构造函数会逐元素地拷贝一个数组类型的成员。

禁用赋值
在C++11的标准中,可以在声明赋值运算符时,在函数参数的右括号后面加=delete,来禁用该类对象的赋值操作,以CDate为例,加了=delete的赋值运算符函数声明如下:

CDate& operator=(const CDate& date) =delete;// 赋值运算符函数声明

有了这个声明后,就不能给CDate对象赋值了。


在这里插入图片描述

🎄五、总结

👉本文主要介绍了C++的拷贝赋值运算符,了解为什么需要拷贝赋值运算符,什么是拷贝赋值运算符,怎样声明、定义、使用拷贝赋值运算符,最后介绍默认的拷贝赋值运算符以及禁用赋值功能。

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

相关文章:

【C++ | 拷贝赋值运算符函数】一文了解C++的 拷贝赋值运算符函数

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a;2024-06-09 1…...

Linux网络安全

文章目录 一、网络安全概述二、常用服务端口三、 ping命令的使用3.1、ping命令的简单概述3.2、ping命令的使用 四、资源限制4.1、查看系统资源限制4.2、临时修改资源限制4.3、永久修改资源限制 五、网络安全服务工具介绍5.1、ClamAV5.2、Nmap5.3、Wireshark5.4、Netcat5.5、Sno…...

Django 视图类

在Django框架中&#xff0c;视图类&#xff08;Class-based views&#xff0c;简称CBVs&#xff09;提供了一个面向对象的方式来定义视图。这种方式可以让你通过创建类来组织视图逻辑&#xff0c;而不是使用基于函数的视图&#xff08;Function-based views&#xff0c;简称FBV…...

【Java面试】十七、并发篇(上)

文章目录 1、synchronized关键字的底层原理&#xff1a;Monitor2、synchronized相关2.1 为什么说synchronized是重量级锁2.2 synchronized锁升级之偏向锁2.3 synchronized锁升级之轻量级锁 3、Java内存模型JMM4、CAS4.1 CAS流程4.2 CAS底层实现 5、volatile关键字的理解5.1 可见…...

七天进阶elasticsearch[one]

elasticSearch 概述 Elasticsearch是一个近实时的搜索平台。这意味着&#xff0c;从索引一个文档直到这个文档能够被搜索到有一个很小的延迟&#xff08;通常是一秒&#xff09; 集群 一个集群就是由一个或多个节点组织在一起&#xff0c; 它们共同持有你全部的数据&#x…...

全新抖音快手小红书视频解析去水印系统网站源码

这个系统支持几十种平台&#xff0c;包括抖音、快手小红书以及其他热门社交媒体平台。它可以帮助轻松地下载这些平台上的任何视频&#xff0c;并去除其中的水印&#xff0c;让你可以自由地保存和分享这些视频。 使用方法&#xff1a; 上传压缩包解压&#xff0c;网站信息在inc…...

图解 Python 编程(12) | 文件和编码方式

&#x1f31e;欢迎来到Python 的世界 &#x1f308;博客主页&#xff1a;卿云阁 &#x1f48c;欢迎关注&#x1f389;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f31f;本文由卿云阁原创&#xff01; &#x1f4c6;首发时间&#xff1a;&#x1f339;2024年6月9日&am…...

CSDN个人主页动态地图(前端/后端)

前段时间有人问我&#xff0c;关于CSDN个人主页动态地图的实现&#xff0c;我来解答一下。 这里要注意一下&#xff1a;使用CSDN的API需要遵循其开发者协议和使用规范&#xff0c;确保你的使用方式符合相关规定 前端部分&#xff1a; 创建一个HTML页面作为个人主页。在页面上放…...

GUI编程-01

组件 窗口 弹窗 面板 文本框 列表框 按钮 图片 监听事件 鼠标 键盘事件 破解工具 Java提供了丰富的图形用户界面&#xff08;Graphics User Interface&#xff0c;GUI&#xff09;的类库&#xff0c;基于这些类库可以编写窗口程序。 Java关于图形界面的类库主要放在…...

Linux网络-自定义协议、序列化和反序列化、网络计算服务器的实现和Windows端客户端

文章目录 前言一、自定义协议传结构体对象 序列化和反序列化什么是序列化&#xff1f;反序列化 二、计算器服务端&#xff08;线程池版本&#xff09;1.main.cc2.Socket.hpp3.protocol.hpp4.Calculator.hpp5.serverCal.hpp6.threadPool.hpp7.Task.hpp8. log.hpp 客户端Windows客…...

Hive知识体系保姆级教程

一. Hive概览 1.1 hive的简介 Hive是基于Hadoop的一个数据仓库工具&#xff0c;可以将结构化的数据文件映射为一张数据库表&#xff0c;并提供类SQL查询功能。 其本质是将SQL转换为MapReduce/Spark的任务进行运算&#xff0c;底层由HDFS来提供数据的存储&#xff0c;说白了h…...

三大网络简介

一、三大网是哪三大网 三大网络为电话网、电视广播网、互联网&#xff0c;如果这三大网络使用都是“ip分组交换”技术的话&#xff0c;他们将会被融合成为一个网络&#xff0c; 但是由于历史原因&#xff0c;他们使用了不同的通信技术&#xff0c;三大网各自拥有相当的独立性&a…...

Element-UI全面入门与实战技巧

本文详细介绍了Element-UI的安装、配置、组件使用、布局技巧、交互设计、表单处理、主题定制等内容&#xff0c;旨在帮助开发者快速掌握Element-UI&#xff0c;并能在实际项目中灵活应用。 文章目录 一、Element-UI概述与安装1.1 Element-UI简介1.2 环境搭建1.3 安装Element-UI…...

第103天: 权限提升-Linux 系统辅助项目脏牛Dirty内核漏洞SUIDGUID

项目下载地址 综合类探针&#xff1a; https://github.com/liamg/traitor 自动化提权&#xff1a; https://github.com/AlessandroZ/BeRoot 信息收集&#xff1a; https://github.com/rebootuser/LinEnum https://github.com/sleventyeleven/linuxprivchecker 漏洞探针&#xf…...

如何用群晖当异地组网服务器?

在当今信息化时代&#xff0c;远程通信成为了企业和个人之间不可或缺的一部分。特别是对于跨地区的通信需求&#xff0c;一个可靠的异地组网服务器是必不可少的。而群晖&#xff08;Synology&#xff09;作为一款功能强大的网络存储设备&#xff0c;可以被用作办公室或家庭的异…...

文件怎么去重?5个技巧,教你删除重复文件!

一般来说&#xff0c;在处理大量文件时&#xff0c;你可能会遇到重复的类似文件。这些文件占据了电脑上不必要的磁盘空间&#xff0c;导致系统性能下降。而这些文件可以是不同类型的&#xff0c;如照片、视频、音频、存档、文档等。正因如此&#xff0c;您需要通过文件去重来删…...

标准发布实施 | 《村镇污水处理一体化集成装备技术规范》

根据《中华人民共和国标准化法》以及国家标准化管理委员会、民政部联合制定的《团体标准管理规定》&#xff0c;依据全国团体标准信息平台和《中华环保联合会团体标准管理办法&#xff08;试行&#xff09;》&#xff0c;全国团体标准《村镇污水处理一体化集成装备技术指南》&a…...

人工智能--教育领域的运用

文章目录 &#x1f40b;引言 &#x1f40b;个性化学习 &#x1f988;体现&#xff1a; &#x1f988;技术解析&#xff1a; &#x1f40b;智能辅导与虚拟助手 &#x1f988;体现&#xff1a; &#x1f988;技术解析&#xff1a; &#x1f40b;自动评分与评估 &#x1f…...

【设计模式深度剖析】【3】【行为型】【职责链模式】| 以购物中心客户服务流程为例加深理解

&#x1f448;️上一篇:命令模式 | 下一篇:策略模式&#x1f449;️ 设计模式-专栏&#x1f448;️ 文章目录 职责链模式定义英文原话直译如何理解呢&#xff1f; 职责链模式的角色1. Handler&#xff08;抽象处理者&#xff09;2. ConcreteHandler&#xff08;具体处理者…...

评价GPT-4的方案

评价GPT-4的方案 引言: 随着人工智能技术的不断发展,自然语言处理领域取得了显著的突破。其中,GPT-4作为最新的大型语言模型之一,备受关注。本方案旨在对GPT-4进行全面评价,包括其技术特点、性能表现、应用场景以及潜在的影响等方面。 一、技术特点 1. 模型规模和参数数…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期&#xff0c;让读者对此有深刻印象。 目录 ​…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...

R 语言科研绘图第 55 期 --- 网络图-聚类

在发表科研论文的过程中&#xff0c;科研绘图是必不可少的&#xff0c;一张好看的图形会是文章很大的加分项。 为了便于使用&#xff0c;本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中&#xff0c;获取方式&#xff1a; R 语言科研绘图模板 --- sciRplothttps://mp.…...