C++类和对象 ——构造函数
C++拷贝构造函数详解
- 什么是拷贝构造函数?
- 拷贝构造函数的特征
- 默认拷贝构造函数
- 为什么需要显示定义构造函数?
- 拷贝构造函数的调用场景
- 什么时候不需要自己定义拷贝构造函数
什么是拷贝构造函数?
在现实生活中,拷贝构造函数就好像我们上学时候干的一件事——抄作业(doge,但在现实生活中,这是件不好的事,但是在类和对象中,拷贝构造函数确是一个作用极大的东西。
在创建对象时,能否船创建一个与已经存在对象一模一样的对象呢?当然可以,这时候就要使用拷贝构造函数了。
拷贝构造函数: 只有单个形参,该形参是对 本类类型对象的引用(一般常用const修饰),在用 已存在的类类型对象创建新对象时由编译器自动调用。
对于内置类型,就相当于int a = b
,这样,用b来构造a
注意: 构造和赋值是两件不一样的事,看下面一段代码:
//拷贝构造
int b = 10;
int a = b;//赋值
int a = 10, b;
b = a;
拷贝构造函数的特征
拷贝构造函数也是特殊的成员函数之一:
- 拷贝构造函数是构造函数的一个重载形式
- 拷贝构造函数的参数只有一个且必须是类对象的引用,使用传值方法编译器会强制检查报错,因为会引发无穷递归问题。
相信这里大家一定会有疑惑,为什么传值的方法会引发无穷递归的问题?
看下面一段代码:
#include<iostream>
class Date
{
private:int _year;int _month;int _day;
public:Date(int year = 1970, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Date(const Date& d){std::cout << "Date(const Date& d)" << std::endl;_year = d._year;_month = d._month;_day = d._day;}
}void func(Date d)
{}int main()
{Date d1(2023,5,1);func(d1);return 0;
}
上面这段代码的运行结果如下:
这说明了什么问题?
我们使用了拷贝构造函数,可是在哪里使用的呢?从代码上看,并没有看到我们使用了拷贝构造啊?
这里就涉及到一个经典的问题了,还记得形参和实参之间的关系吗?没错,就是她俩在搞鬼!!
- 形参是实参的临时拷贝!!!
- 形参是实参的临时拷贝!!!
- 形参是实参的临时拷贝!!!
重要的事情说三遍,没错!正是因为这个性质,在调用func
函数时,我们将d1传给形参d,就发生了用d1来拷贝复制形参的出现,那么有了这一个理解,我们就能了解为什么在设计拷贝构造函数的时候不能使用传值调用了。
因为如果用传值调用,效率不高是一个,另外一个就是调用拷贝复制函数时,形参和实参之间的复制需要一直调用拷贝构造,就会出现无限递归的情况,具体看下图:
因此,现在的编译器为了避免这种无限递归的产生,会对复制构造函数传值的设计进行强制的检查,一旦我们用传值的方式设计拷贝构造函数,将无法完成编译。
默认拷贝构造函数
若未显示定义,编译器会生成默认的拷贝构造函数。默认的拷贝构造函数对象对内置类型是按照字节方式直接拷贝的(这种拷贝又叫做浅拷贝,或者叫值拷贝),而对自定义类型是调用其拷贝构造函数来完成拷贝的。
在前面日期类的基础上,我们再创建一个类,来测试一下这个特性。
#include<iostream>
class Date
{
private:int _year;int _month;int _day;
public:Date(int year = 1970, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Date(const Date& d){std::cout << "Date(const Date& d)" << std::endl;_year = d._year;_month = d._month;_day = d._day;}
};
class Time
{
private:int hour;int min;int second;Date x;
};int main()
{Time d1;Time d2(d1);return 0;
}
可以看到,我们并没有定义Time类的拷贝构造,所以使用的是系统自动生成的默认拷贝构造函数,而从运行结果看其确实符合上诉所说的特性。
为什么需要显示定义构造函数?
大家刚接触到拷贝构造函数的时候一定有一个问题,竟然编译器生成的拷贝构造函数已经可以完成字节序的值拷贝了,那还需要显示定义吗?也许对日期类这种比较简单的类不需要,那如果是更复杂的一些类呢?看下面的例子:
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;
}
上面这段代码在运行之后将会崩溃,为什么呢?我们首先来看看定义的两个stack对象里保存的东西:
两个对象动态申请的数组指向同一块空间,这就是默认拷贝构造函数带来的后果,而如此造成的结果并不是我们想要的,在程序结束调用析构的时候,将会对同一块空间释放两次,因此会造成错误。
因此,类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构 造函数是一定要写的,否则就是浅拷贝。
拷贝构造函数的调用场景
- 使用已存在对象创建新对象
- 函数参数为类类型对象(形参的拷贝创建)
- 函数返回值类型为类类型对象(创建临时变量)
什么时候不需要自己定义拷贝构造函数
- 类成员都是自定义类型
- 所有的成员都只需要浅拷贝就能完成任务
好了,以上就是这篇博客的全部内容,如果大伙发现博主哪里写的有问题或者有疑惑的话,欢迎评论区指出!😘
相关文章:

C++类和对象 ——构造函数
C拷贝构造函数详解 什么是拷贝构造函数?拷贝构造函数的特征默认拷贝构造函数为什么需要显示定义构造函数?拷贝构造函数的调用场景什么时候不需要自己定义拷贝构造函数 什么是拷贝构造函数? 在现实生活中,拷贝构造函数就好像我们上…...
第2章-分治法
第2章-分治法 总分:100分 得分:20.0分 1 . 多选题 中等 10分 有关以下代码,说法正确的是( ABCE) def BinarySearch(s, x, low, high):if (low > high):return -1middle (low high) / 2if (x s[mid…...

20天能拿下PMP吗?
新版大纲,专注于人员、过程、业务环境三个领域,内容贯穿价值交付范围(包括预测、敏捷和混合的方法)。除了考试时间由240分钟变更为230分钟、200道单选题变为180道(包含单选和多选)之外,新考纲还…...

Word处理控件Aspose.Words功能演示:在 Java 中将 Word DOC/DOCX 转换为 PDF
Aspose.Words是一种高级Word文档处理API,用于执行各种文档管理和操作任务。API支持生成,修改,转换,呈现和打印文档,而无需在跨平台应用程序中直接使用Microsoft Word。 Aspose API支持流行文件格式处理,并…...

数据安全的重要性
数据安全非常重要,因为我们生活在数字化时代,许多信息和数据都以数字形式存储和传输。如果这些数据受到未经授权的访问、篡改、泄露或破坏,会对个人、组织和国家造成严重的损失。 以下是数据安全的重要性: 1. 保护各类隐私&#x…...

要创建富文本内容?Kendo UI Angular组件有专门的编辑器应对!
您的Angular应用程序可能需要允许用户添加带有格式化选项的文本、图像、表格、外观样式和/或链接,使用Kendo UI for Angular的编辑器,可以轻松搞定这些! Kendo UI for Angular是专业级的Angular UI组件库,不仅是将其他供应商提供…...

工赋开发者社区 | 装备制造企业数字化转型总体框架
导读 当前,面对技术、市场以及供应链等多重挑战,在软件定义、数据驱动、数字孪生、大数据、人工智能及元宇宙等技术加持下,装备制造企业不断采用新工艺、新材料,以新模式推动产品快速创新。企业积极关注并探索数字化转型路径&…...

Python趋势外推预测模型实验完整版
趋势外推预测模型实验完整版 实验目的 通过趋势外推预测模型(佩尔预测模型),掌握预测模型的建立和应用方法,了解趋势外推预测模型(佩尔预测模型)的基本原理 实验内容 趋势外推预测模型 实验步骤和过程…...
KALI入门到高级【第三章】
预计更新第一章 入门 1.1 什么是Kali Linux? 1.2 安装Kali Linux 1.3 Kali Linux桌面环境介绍 1.4 基本命令和工具 第二章 信息收集 1.1 网络扫描 1.2 端口扫描 1.3 漏洞扫描 1.4 社交工程学 第三章 攻击和渗透测试 1.1 密码破解 1.2 暴力破解 1.3 漏洞利用 1.4 特…...

React Native中防止滑动过程中误触
React Native中防止滑动过程中误触 在使用React Native开发的时,当我们快速滑动应用的时候,可能会出现误触,导致我们会点击到页面中的某一些点击事件,误触导致页面元素响应从而进行其他操作,表现出非常不好的用户体验。 一、问题…...

【c语言】函数递归调用
创作不易,本篇文章如果帮助到了你,还请点赞 关注支持一下♡>𖥦<)!! 主页专栏有更多知识,如有疑问欢迎大家指正讨论,共同进步! 给大家跳段街舞感谢支持!ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ…...

SPSS如何进行判别分析之案例实训?
文章目录 0.引言1.一般判别分析2.逐步判别分析3.决策树分析 0.引言 因科研等多场景需要进行绘图处理,笔者对SPSS进行了学习,本文通过《SPSS统计分析从入门到精通》及其配套素材结合网上相关资料进行学习笔记总结,本文对判别分析进行阐述。 1…...
Windows 10 字体模糊发虚的问题及解决方法
Windows 10字体模糊发虚! 如何解决?Windows 10是一款常见的操作系统,它拥有各种各样的功能,但是有些用户发现,在使用Windows 10时,字体会变得模糊发虚,这给用户带来了很多不便。下面,我们就来看看如何解决…...
渔人杯部分wp
文章目录 渔人杯神仙姐姐阿拉丁飘啊飘 渔人杯 神仙姐姐 点击拜 ,抓包发现get请求了/sx.php 返回如下 {"code":0,"num":1,"flag":"ctfsh0w-f1ag-n0t-h3r3-th1s-msg-just-a-j0ke-}{"}在repeater重复请求,发现…...

测试用例覆盖不全面的解决方法
测试用例覆盖不全面的解决方法 问题分析 在测试用例设计过程中,容易出现思维受限或者需求盲区,我们不可能完全覆盖用户使用的所有场景,编写测试用例的时不可能把所有的场景都能想周全,把所有的场景下的情况都写成测试用例去模拟、…...

AWS Lambda - 第一部分
Hello大家好,我们今天开始讨论AWS Lambda的内容。 SAP认证考试会涉及到很多Lambda的内容,想要通过认证考试虽然不一定非要精通开发,但需要知道Lambda的一些功能和特性、适用场景以及Lambda是如何工作的。 我们开始吧! Lambda与…...

Java 基础进阶篇(七)—— 面向对象三大特征之三:多态
文章目录 一、多态的概述二、多态中成员访问特点 ★三、多态的优势与劣势四、多态下的类型转换4.2 自动类型转换(从子到父)4.2 强制类型转换(从父到子)4.3 instanceof 关键字 一、多态的概述 多态:是指执行同一个行为…...

day9 实现UDP通信
目录 socket函数拓展 UDP通信实现过程 代码实现 socket函数拓展 send与recv函数: /*用于发送数据*/ ssize_t send(int sockfd, const void *buf, size_t len,int flags);/*用于接收数据*/ ssize_t recv(int sockfd, void *buf, size_t len,int flags);/*前三个…...

自然语言处理(NLP)在放射学报告评价中的应用:应用和技术进展
自然语言处理(NLP)在放射学报告评价中的应用:应用和技术进展 写在最前面摘要引言先进的技术BERT算法优点 Applications in Radiology 放射学应用Quality 质量将关键发现通知转诊临床医生放射科关键绩效指标和评估 个别放射科医生的表现同行学…...

日常开发为什么需要做Code Review
日常开发为什么需要做Code Review 一、背景 最近在开始一个新的项目,在查看项目中代码及具体细节时,发现这个项目真实一堆乱麻,没有规律可循,可总结下这个项目的缺陷 没有规律可循,没有结构性设计不做公共封装&#…...

【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
二维FDTD算法仿真
二维FDTD算法仿真,并带完全匹配层,输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...