C++ 拷贝构造函数和运算符重载

news2024/12/26 14:24:21

目录

一. 拷贝构造函数

1. 引入

2. 拷贝构造的概念

3. 浅拷贝

4. 深拷贝

二. C++运算符重载 

1. 概念 

2. 注意事项 

3.举例 


一. 拷贝构造函数

1. 引入

我们在创建对象时,能不能创建一个与原先对象一模一样的新对象呢?为了解决这个问题,C++提出了拷贝构造的概念。

2. 拷贝构造的概念

当我们想把一个对象赋值给另一个对象或者创建一个与已存在对象一某一样的新对象时需要调用它的拷贝函数来进行复制。我们以下面的代码举例:

#include<iostream>
using namespace std;

class Date 
{
public:
	Date(int year = 2024, int month = 3, int day = 14)
	{
		_year = year;
		_month = month;
		_day = day;
	}
    // Date(const Date d)    // 错误写法:编译报错,会引发无穷递归
	Date(const Date& d)//拷贝构造函数
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	Date d2(d1);
//这样写也可以:Date d2 = d1;
	return 0;
}

拷贝构造函数也是特殊的成员函数,其特征如下:

1. 拷贝构造函数是构造函数的一个重载形式。

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

为什么会引发无穷递归呢?是因为如果我们传值当形参的话那么形参是实参的一份临时拷贝又会拷贝构造函数这样就会无限递归下去。

所以我们在书写构造函数的时候一定要使用传引用当做形参。 

 

3. 浅拷贝

我们知道C语言函数在传递参数时,会将实参的值传递给形参,中间自动存在一个变量的临时拷贝过程,那如果我们不写拷贝构造函数,编译器会发生什么情况呢?

我们发现仍然完成了值拷贝。这是因为拷贝构造函数没有显示定义的化,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。需要注意的是,在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定义类型是调用其拷贝构造函数完成拷贝的。

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(s1);
	return 0;
}

这里刚开始创建了一个S1 对象,又创建了一个S2 对象去进行调用拷贝构造函数进行拷贝,而这里只进行了浅拷贝,在 S2 进行拷贝构造的时候只是简单的把值复制过去了所以 S2 和 S1 是指向同一块空间并没有给 S2 去单独开辟一个一模一样的空间。那为什么程序回出现崩溃呢?

S2 和 S1 指向用一块空间而当程序结束的时候 S2 调用它的析构函数去吧 S1 所指向的空间给释放了, 那么当 S1 在释放的时候就重复释放了原来释放的空间导致程序崩溃。一块空间不能被释放两次。

因此我们我们需要进行深拷贝:

#include<iostream>
#include<stdlib.h>
using namespace std;

class Stack
{
public:
	Stack(size_t capacity = 10)
	{
		_array = (int*)malloc(capacity * sizeof(int));
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
			return;
		}

		_size = 0;
		_capacity = capacity;
	}
	Stack(const Stack& p1)
	{
		int* tmp = (int*)malloc(sizeof(int) * p1._capacity);
		if (tmp == nullptr)
		{
			perror("file malloc");
			exit(-1);			

		}

		memcpy(tmp, p1._array, sizeof(int) * p1._size);

		_array = tmp;
		_capacity = p1._capacity;
		_size = p1._size;
		
	}
	void Push(const int& data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}
	~Stack()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	int* _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(s1);
	return 0;
}

所以我们需要动态申请空间,显示定义拷贝构造函数,把空间大小和值内容拷贝进去。

因此我们有以下总结: 

类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请 时,则拷贝构造函数是一定要写的,否则就是浅拷贝。拷贝构造函数典型调用场景:使用已存在对象创建新对象 函数参数类型为类类型对象 ,函数返回值类型为类类型对象。

二. C++运算符重载 

1. 概念 

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其 返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。 函数名字为:关键字operator后面接需要重载的运算符符号。

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

2. 注意事项 

 不能通过连接其他符号来创建新的操作符:比如operator@

重载操作符必须有一个类类型参数 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义

作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this

以上下个运算符不能重载:

3.举例 
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	int _year;
	int _month;
	int _day;
};

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

int main()
{
	Date d1(2024, 3, 14);
	Date d2(2024, 3, 15);
	cout << (d1 == d2) << endl;
	return 0;
}


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

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

相关文章

Qt/QML编程之路:基于QWidget编程及各种2D/3D/PIC绘制的示例(45)

关于使用GWidget,这里有一个示例,看了之后很多图形绘制,控件使用,及最基本的QWidget编程都比较清楚了。ui的绘制: 运行后的界面如 工程中有非常丰富的关于各种图形的绘制,比如上图中circle,还有image。有下面一段readme的说明: # EasyQPainter Various operation pra…

java数据结构与算法刷题-----LeetCode47. 全排列 II

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 1. 暴力回溯2. 分区法回溯 此题为46题的衍生题&#xff0c;在46题…

QT c++ 双精度数拆分和组合 Tool

本文描述QT c的双精度数拆分和合并&#xff0c;即双精度浮点数拆为四个16位无符号整数以及将四个16位无符号整数组合为双精度浮点数。 开发平台&#xff1a;win10QT6.2.4 MSVC2019 64 bit 在本文的最好列出了代码和可执行文件打包下载链接&#xff08;可直接使用&#xff09;…

【数学】【计算几何】1453. 圆形靶内的最大飞镖数量

作者推荐 视频算法专题 本文涉及知识点 数学 计算几何 LeetCoce:1453. 圆形靶内的最大飞镖数量 Alice 向一面非常大的墙上掷出 n 支飞镖。给你一个数组 darts &#xff0c;其中 darts[i] [xi, yi] 表示 Alice 掷出的第 i 支飞镖落在墙上的位置。 Bob 知道墙上所有 n 支飞…

“计算机行业的未来:政策导向、技术创新与发展前景“

从政府工作报告探计算机行业发展 政府工作报告作为政府工作的全面总结和未来规划&#xff0c;不仅反映了国家整体的发展态势&#xff0c;也为各行各业提供了发展的指引和参考。随着信息技术的快速发展&#xff0c;计算机行业已经成为推动经济社会发展的重要引擎之一。因此&…

Hack The Box-Monitored

目录 信息收集 rustscan dirsearch WEB web信息收集 snmpwalk curl POST身份验证 漏洞探索 漏洞挖掘 sqlmap 登录后台 提权 get user get root 信息收集 rustscan ┌──(root㉿ru)-[~/kali/hackthebox] └─# rustscan -b 2250 10.10.11.248 --range0-65535 --…

攻防世界-misc-arrdeepee

题目链接:攻防世界 (xctf.org.cn) 题目:我们某一个box被pwn了。在检查过程中,我们发现了一个叫mimikatz的东西,我们以前没有安装过,所以我们清除了,并且重新安装了box。但是,我们忘记备份我们的flag文件了。幸运的是,我们有一个攻击者网络流量捕获。你可以帮我们恢复出…

第12集《天台教观纲宗》

请大家打开讲义第二十一页&#xff0c;我们看己二、明稍利随时得入。 蕅益大师在《弥陀要解》讲一个很重要的概念&#xff0c;提醒所有净土宗的行者&#xff0c;他说&#xff1a;方便有多门&#xff0c;归元无二路。学佛它有两个概念&#xff1a;一个是方便&#xff0c;一个是归…

Android 录屏操作

Android 录屏操作 本文主要介绍android中如何通过MediaRecorder实现录屏操作的. 1: 申请权限 <uses-permission android:name"android.permission.RECORD_AUDIO" /> <uses-permission android:name"android.permission.WRITE_EXTERNAL_STORAGE"…

vue3动态组件未渲染问题

渲染问题 component动态组件写法与vue2写法一致&#xff0c;代码如下&#xff1a; <component :is"componentName"/><script setup>import { ref } from vueimport account from ./user/account.vue// 组件名称const componentName ref(account)// 点击…

密码学——MAC

消息认证码 在信息发送和接收过程中,若攻击者能够得到信息,进行篡改,就能达到欺骗,诈骗,冒名顶替的作用。为了防止冒名诈骗,一个对策就是使用消息认证码——MAC: Message Authentication Code。 消息认证码,即确定消息真实性的认证程序。发件人将想要发送的信息和从哪个…

挑战OpenAI的新模型免费上线,40%计算量性能逼近GPT-4

据介绍,Inflection-2.5 将强大的 LLM 能力与 Inflection 标志性的「同理心微调」结合在一起,兼具高情商与高智商,可联网获取事实信息,其性能可与 GPT-4、Gemini 等领先大模型相媲美。 本周四,美国 AI 创业公司 Inflection AI 正式发布新一代大语言模型 Inflection-2.5。 …

es 聚合操作(二)

书接上文&#xff0c;示例数据在上一篇&#xff0c;这里就不展示了 一、Pipeline Aggregation 支持对聚合分析的结果&#xff0c;再次进行聚合分析。 Pipeline 的分析结果会输出到原结果中&#xff0c;根据位置的不同&#xff0c;分为两类&#xff1a; Sibling - 结果和现有…

Github 2024-03-15 开源项目日报 Top10

根据Github Trendings的统计,今日(2024-03-15统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量TypeScript项目3Python项目3非开发语言项目2PHP项目1C#项目1Rust项目1《Hello 算法》:动画图解、一键运行的数据结构与算法教程 创建周期:476…

N沟道功率MOSFET--FDA59N30 助力提高电源效率 为设备节能做出贡献

FDA59N30 UniFETTM MOSFET 是高压 MOSFET产品&#xff0c;基于平面条形和 DMOS 技术。 该 MOSFET 产品专用于降低通态电阻&#xff0c;并提供更好的开关性能和更高的雪崩能量强度。适用于开关电源转换器应用&#xff0c;如功率因数校正&#xff08;PFC&#xff09;、平板显示器…

c++简单使用

取消同步流是为了解决C有时遇到空格或回车&#xff08;不到\0&#xff09;就会停下的问题 #include<bits/stdc.h> using namespace std; int main() {//取消同步流ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int a, b;cin >> a>> b;cout << …

上海亚商投顾:沪指三连阴 创新药、资源回收概念逆势走强

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 三大指数昨日冲高回落&#xff0c;深成指、创业板指午后跌超1%&#xff0c;临近尾盘跌幅有所收窄。创新药板块…

kyuubi整合微服务效果整理

目录 概述展示整合效果nacosadmin server请求 结束 概述 在各种奇葩需求之下&#xff0c;公司大数据&#xff0c;在资源不够的情况下&#xff0c;还要做资源高配的负载均衡&#xff0c;虽说非正道。但还是试一下。 展示 整合 整合 nacos 做资源配置动态刷新整合 spring boo…

Spring Boot 中@Scheduled是单线程还是多线程?

在开发Spring Boot应用程序时&#xff0c;定时任务是一项常见的需求。Spring Boot提供了Scheduled注解&#xff0c;可用于将方法标记为定时任务&#xff0c;并在预定的时间间隔内执行。那么Scheduled注解的执行方式是单线程执行&#xff0c;还是多线程执行&#xff1f;Schedule…

【Redis】Redis常用命令之Hash

1.hset&#xff1a;设置hash中指定的字段&#xff08;field&#xff09;的值&#xff08;value&#xff09;。 HSET key field value [field value ...]时间复杂度&#xff1a;插⼊⼀组field为O(1),插⼊N组field为O(N)。 返回值&#xff1a;添加的字段的个数。 2.hget&#xf…