拷贝构造函数与运算符重载

目录

一、拷贝构造函数

1.概念

2.特性

二、运算符重载 

1.运算符重载

2.运算符重载实现的形式 

3.赋值运算符重载 


一、拷贝构造函数

1.概念

拷贝构造函数是一种特殊的构造函数,它在创建对象时,使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数通常用于通过使用另一个同类型的对象来初始化新对象,或者在函数间传递对象时复制对象的状态。

拷贝构造函数只有单个形参,该形参是对本类类型对象的引用(一般用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。

2.特性

①拷贝构造函数是构造函数的一个重载形式

拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器会直接报错,因为会引发无穷递归调用

③若未显式定义,编译器会生成默认的拷贝构造函数。默认的拷贝构造函数对象按内存存储字节序完成拷贝,这种拷贝叫做浅拷贝(值拷贝)

④编译器生成的默认拷贝构造函数中,内置类型直接拷贝,自定义类型调用其拷贝构造函数(与析构函数类似)

接下来对这些特性进行详细讲解:

关于第①点:

我们知道,构造函数的作用就是初始化,而我们在实例化出对象时是可以有多种初始化方式的,即构造函数支持重载,而拷贝构造函数就是将一个已经创建好的对象来初始化一个即将创建的对象,调用拷贝构造函数后这两个对象中的成员变量的值就是一样的。

关于第②点(重点):

我们先来看看拷贝构造函数的一般形式:

类名(const 类名& 其他对象)

参数为什么一定要是引用呢?直接传对象不可以吗?

我们知道,形参是实参的临时拷贝,如果是传值的话,在执行函数体中的语句前需要先拷贝实参给形参,而在拷贝构造函数中,参数是一个对象,要拷贝实参给形参就需要再次调用拷贝构造函数,而在这个函数中参数又是对象,就又要调用拷贝构造函数,就会一直这样无穷递归调用下去。

接下来看草图来帮助理解:

 在拷贝构造函数中,我们不希望所传入的参数(对象)被修改,所以要加上const。

关于第③点:

当我们没有写拷贝构造函数时编译器会自动生成一个拷贝构造函数,接下来我们看一段代码来验证:

#include <iostream>
using namespace std;

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

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

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

int main()
{
	Date today(2024, 4, 17);
	Date _today(today);
	today.Print();
	_today.Print();
	return 0;
}

运行结果: 

可以看到,_today最后初始化为与today一样了,说明调用了编译器自动生成的拷贝构造函数。

既然我们不写拷贝函数时,编译器可以帮助我们生成一个拷贝函数,那么是否我们就不需要写拷贝构造函数了呢?

答案肯定是否定的,因为编译器生成的拷贝构造函数只能实现浅拷贝,接下来就要详细讲解一下浅拷贝和深拷贝的区别了。

浅拷贝仅复制对象中的数据成员,而不涉及动态内存分配;深拷贝则会创建一个新的对象并在堆上分配内存,以复制原始对象中的动态内存部分。

也就是说,浅拷贝只能拷贝数据成员,如果对象申请了空间,是无法自动在堆区中申请空间的。

总结:

①如果不涉及到申请空间(资源),可以不用写拷贝构造,编译器自动生成的就可以

②如果全是自定义类型成员,内置类型成员没有指向资源,用生成的默认拷贝构造函数就可以

③如果内部有指针或者一些值指向资源,就需要显式写析构函数,一般需要显式写析构函数的就需要显式写拷贝构造函数

二、运算符重载 

1.运算符重载

运算符重载(Operator Overloading)是C++语言的一个强大特性,它允许程序员为自定义类型重新定义或重载已有的运算符,使得这些运算符能够用于自定义类型的对象。通过运算符重载,我们可以使得自定义类型的对象操作起来像内置类型(如int、float等)一样直观和方便。

运算符重载是具有特殊函数名的函数,也具有其返回类型,函数名字以及参数列表,其返回值类型是与参数列表与普通的函数类似。

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

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

注意:

①重载运算符时,只能重载现有的运算符

②不能改变运算符的性质,如:运算符的优先级、结合性、操作数的个数及其语法结构

③五个不能重载的运算符:.   .*   ::   ?:   sizeof

2.运算符重载实现的形式 

要重载一个运算符,可以把该运算符函数定义为类的成员函数,也可以把该运算符函数定义为类的非成员函数。非成员函数的形式通常包括友元函数和全局函数等两种形式。一般来说,把运算符函数定义为类的成员函数和友元函数,具有更简单的成员设置要求和更高的成员访问效率。

大多数运算符可以同时用成员函数形式和友元函数形式重载,如加法、减法、乘法和除法等算术运算符。但是=  ()  []  ->只能重载为类的成员函数

需要注意的是,如果重载为成员函数,实际参数数要少一个,因为有一个隐含的this指针,指向当前对象。

例如有一个Date类,重载>并且将其作为成员函数,实际只需要传一个参数:

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

	bool operator>(const Date& x)
	{
		//年大就大
		if (_year > x._year)
		{
			return true;
		}
		else if (_year == x._year)
		{
			//年相同,月大就大
			if (_month > x._month)
			{
				return true;
			}
			else if (_month == x._month)
			{
				return _day > x._day;
			}
		}

		return false;
	}

3.赋值运算符重载 

同样,我们先把所需要的注意点放前边总结,然后再详细讲解。

①参数类型:const T&,传引用可以提高效率(T是类名)

②返回类型:T&,避免再一次拷贝,提高效率

③避免自赋值

④赋值运算符只能重载为类的成员函数

⑤我们平时使用的赋值运算符=是可以连等的,重载时也应该保留这个特点

⑥用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝,内置类型成员变量是直接赋值的,而自定义类型需要调用对应类的赋值运算符重载完成赋值

 关于第①②点:

在传参和值返回时会创建临时变量,也就是说,如果我们返回类型是类类型,那么就会再一次调用拷贝构造函数,这种是不必要的,所以用引用的形式返回更高效。

需要注意的是,并不是什么时候都可以用引用返回,出了作用域,返回对象还没有析构,就可以用引用返回,减少拷贝,如果返回对象已经析构,就不能用引用返回

我们来看下边的代码,在Test函数中,我们创建了一个日期对象d,并且返回它的引用,然后在主函数中用dd再来接收(相当于Date& tmp = d; Date& dd = tmp;tmp是d的别名,dd是tmp的别名,即dd也是d的别名),按道理说d是2024年4月19日,而Test返回的是引用即别名,dd应当与d相同才是,实际上并不是这样的。原因在于d在执行完Test函数后就被析构了,然后这块内存就会被释放回栈中,当我们再调用其他函数(在这个例子中是Add)时就可能会用到那块空间,这时候就会出现如下的情况:dd中的数据成员全是随机值。

 关于第④点:

赋值运算符如果不显式实现,编译器会生成一个默认的,此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,所以赋值运算符重载只能是类的成员函数。

关于第⑤点:

 对于基本数据类型,是支持连等的,例如有两个int类型的数据a、b,我们可以写a=b=1;赋值运算符=的运算顺序是从右至左,所以实际返回的是左操作数,即我们重载函数时也要返回左操作数,即*this。

接下来我们来实现赋值运算符重载:

在类中再加一个成员函数:

Date& operator=(const Date& x)
{
	if (this != &x)
	{
		_year = x._year;
		_month = x._month;
		_day = x._day;
	}
	return *this;
}

 关于第⑥点:

与拷贝构造函数非常类似,如果未涉及到资源管理,赋值运算符重载是否实现都可以,一旦涉及到资源管理就必须自己实现。

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

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

相关文章

C# 动态加载dll

方式1 using System; using System.Reflection;class Program {static void Main(){string dllPath "path/to/your/library.dll"; // 替换为你的DLL文件路径Assembly myAssembly Assembly.LoadFile(dllPath);Type myType myAssembly.GetType("YourNamespace…

力扣—2024/4/18—从双倍数组中还原原数组

代码实现&#xff1a; 快排 哈希表 ——超时 /*** Note: The returned array must be malloced, assume caller calls free().*/ void swap(int *m, int *n) {int temp *m;*m *n;*n temp; }// 快排 void sort(int *a, int l, int r) { // 左闭右开if (r - l < 2) {if (r…

MIMO(多天线)通信的四种译码算法

目录 一. 介绍 二. 极大似然译码 三. 破零译码算法 四. 最小均方误差算法 五. 球形译码 一. 介绍 发射天线数记为Mt&#xff0c;接收天线数记为Mr。由此发射信号x为向量&#xff1a; 接受信号y为向量&#xff1a; 信道H为矩阵&#xff1a; 利用n代表噪声向量&#xff0c;…

axios的封装理解和基本使用

axios的配置 ruoyi的前端对axios进行了封装&#xff0c;让我们发get请求或者是post请求更加方便了。 ruoyi对axios的封装在下面文件中&#xff1a;打开文件&#xff0c;可以看到它有三个显眼的方法&#xff0c;分别是request拦截器、response拦截器和通用下载方法。ruoYi接口地…

CommunityToolkit.Mvvm笔记---ObservableValidator

ObservableValidator 是实现 INotifyDataErrorInfo 接口的基类&#xff0c;它支持验证向其他应用程序模块公开的属性。 它也继承自 ObservableObject&#xff0c;因此它还可实现 INotifyPropertyChanged 和 INotifyPropertyChanging。 它可用作需要支持属性更改通知和属性验证的…

Redis中的Lua脚本(五)

Lua脚本 脚本复制 复制EVALSHA命令 EVALSHA命令式所有与Lua脚本有关的命令中&#xff0c;复制操作最复杂的一个&#xff0c;因为主服务器与从服务器载入Lua脚本的情况可能有所不同&#xff0c;所以主服务器不能像复制EVAL命令、SCRIPT LOAD命令或者SCRIPT FLUSH命令那样&…

2024 Polkadot Decoded 大会亮点前瞻,立即预定参会席位

原文&#xff1a;https://medium.com/polkadotnetwork/polkadot-decoded-2024-uniting-innovators-in-blockchain-technology-75fc3d8e93fe 作者&#xff1a;Polkadot 编译&#xff1a;OneBlock Polkadot 生态宣布他们的旗舰活动 —— Polkadot Decoded 将再次举行&#xff…

跟TED演讲学英文:How AI could empower any business by Andrew Ng

How AI could empower any business Link: https://www.ted.com/talks/andrew_ng_how_ai_could_empower_any_business Speaker: Andrew Ng Date: April 2022 文章目录 How AI could empower any businessIntroductionVocabularyTranscriptSummary后记 Introduction Expensiv…

von Mises-Fisher Distribution (Appendix 2)

5.3 Fast Python Sampler of the von Mises Fisher Distribution [3] 从论文中 p r o c e d u r e A n g l e G e n e r a t o r ( d , κ ) procedure~AngleGenerator(d, κ) procedure AngleGenerator(d,κ) 中的变换来看, 假设 y ∼ B e ( m − 1 2 , m − 1 2 ) y \sim …

Linux【实战】—— LAMP环境搭建 部署网站

目录 一、介绍 1.1什么是LAMP&#xff1f; 1.2LAMP的作用 二、部署静态网站 2.1 虚拟主机&#xff1a;一台服务器上部署多个网站 2.1.1 安装Apache服务 2.1.2 防火墙配置 2.1.3 准备网站目录 2.1.4 创建网站的配置文件 2.1.5 检查配置文件是否正确 2.1.6 Linux客户端…

【华为 ICT HCIA eNSP 习题汇总】——题目集17

1、以下哪项不属于网络层安全威胁&#xff1f; A、DDos攻击 B、钓鱼攻击 C、IP Spoofing D、IP地址扫描 考点&#xff1a;网络安全 解析&#xff1a;&#xff08;B&#xff09; 钓鱼攻击通常被认为是应用层的安全威胁&#xff0c;也有在网络层进行伪装实施钓鱼攻击&#xff0c;…

TCP/IP常用协议栈图解

1.引言 最近看了一些计算机网络的课程&#xff0c;总结借鉴了一些TCP/IP常用协议&#xff0c;罗列在以下图中&#xff0c;以便有一个整体观。 2.图解 先上图 3.总结 TCP/IP协议是实际用的计算机网络通信的标准协议栈&#xff0c;自上而下分为应用层&#xff0c;传输层&#xf…

关于二级指针void**的一点问题与思考

前言 这两天写一个高并发内存池的项目时&#xff0c;遇到了一个关于二级指针的问题&#xff0c;剖析清楚后发觉有必要记录一下&#xff0c;这让我加深了对于C/C中指针的理解&#xff08;果然学到老活到老&#xff09;。 问题的分析 在我的内存池项目中&#xff0c;有一个需求…

【TEE论文】IceClave: A Trusted Execution Environment for In-Storage Computing

摘要 使用现代固态硬盘&#xff08;SSD&#xff09;的存储中计算使开发人员能够将程序从主机转移到SSD上。这被证明是缓解I/O瓶颈的有效方法。为了促进存储中计算&#xff0c;已经提出了许多框架。然而&#xff0c;其中很少有框架将存储中的安全性作为首要任务。具体而言&…

WebLogic 数据源连接泄露

编码时&#xff0c;有时会忘记释放使用的数据源连接&#xff0c;造成连接泄露&#xff0c;没有连接资源可用。 现象 java.sql.SQLException: Cannot obtain XAConnectionat weblogic.jdbc.jta.DataSource.refreshXAConnAndEnlist(DataSource.java:1691)at weblogic.jdbc.jta.…

ssm062会员管理系统+jsp

会员管理系统 摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于会员管理系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了会员管理系统&#xff0c;它彻底改…

Java项目引入log4j2

log4j2 单独使用 引入依赖 <dependencies><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.14.0</version></dependency><dependency><groupId>o…

[管理者与领导者-174] :人际网络-1- 网络概述,是由一个个人组成的网络,每个节点是“人”

目录 一、数据通信网络 二、移动通信网络 三、人际网络 四、计算机网络与人际网络的比较 五、人际网络中节点-人的分层架构 5.1 人&#xff08;节点&#xff09;的分层架构&#xff1a;个体生理、个体心理、人际关系、社会功能 5.2 什么是人性 5.3 人性的特点 5.3 人性…

智能化新浪潮:国产智能体势在必行,一探究竟!

回顾之前的文章 GPTs大爆发&#xff1a;我的智能助手累计使用71k&#xff0c;荣登全球排名79&#xff0c;我们已经见证了智能助手的强劲增长势头。今天&#xff0c;我兴奋地分享一个新的里程碑&#xff1a;我的GPTs使用量已经突破10万次&#xff0c;排名再次提升&#xff01; 接…

盲人出行新助手:无障碍技术的进步

作为一名资深记者&#xff0c;我始终关注着社会弱势群体的生活权益&#xff0c;尤其是对于视障人士这一特殊群体。在科技日新月异的今天&#xff0c;我们欣喜地看到&#xff0c;盲人无障碍设施这一概念正在以更为先进、人性化的形式实现落地&#xff0c;其中&#xff0c;一款名…
最新文章