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

C++的拷贝构造函数

目录

  • 拷贝构造函数
    • 一、为什么用拷贝构造
    • 二、拷贝构造函数
      • 1、概念
      • 2、特征
        • 1. 拷贝构造函数是构造函数的一个重载形式。
        • 2. 拷贝构造函数的参数
        • 3. 若未显式定义,编译器会生成默认的拷贝构造函数。
        • 4. 拷贝构造函数典型调用场景

拷贝构造函数

一、为什么用拷贝构造

日期类传值(这里是浅拷贝)

#include<iostream>
using namespace std;
class Date {
public:Date(int year=1, int month=1, int day=1) {_year = year;_month = month;_day = day;}void Print() {cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year ;int _month ;int _day ;
};
int main() {Date d1;d1.Print();return 0;
}

运行后:
在这里插入图片描述

这里进行了传值的拷贝,形参传给实参,进行了值拷贝,也就是浅拷贝,所以并没有出现问题。

但是栈类的结构浅拷贝会出现问题

#include<iostream>
using namespace std;class Stack{public:Stack(size_t capacity = 3){cout << "Stack(size_t capacity = 3)" << endl;_a = (int*)malloc(sizeof(int) * capacity);if (nullptr == _a){perror("malloc申请空间失败!!!");}_capacity = capacity;_top = 0;}~Stack(){cout << "~Stack()" << endl;free(_a);_capacity = _top = 0;_a = nullptr;}private:int* _a;int _capacity;int _top;};
int main() {Stack st1;Stack st2(st1);return 0;
}

运行后会变成
在这里插入图片描述
从上面我们可以看出程序崩溃了,这是为什么呢?
原因在于我们的栈的结构体类型中有一个指针来指向下一个结构体,当我们进行浅拷贝的时候会将这个地址也拷贝过去,但是我们的c++会自动调用析构函数,那么析构函数就被调用了两次,从上面的图中我们也可以看出来析构函数被调用了两次,所以程序崩溃了。

那么如何解决这个问题呢,我们的C++祖师爷,就定义了一个拷贝构造函数 来解决这个问题。

二、拷贝构造函数

1、概念

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

2、特征

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

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

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

下面写一个拷贝构造函数重新进行运行:

#include<iostream>
using namespace std;class Stack{public:Stack(size_t capacity = 3){cout << "Stack(size_t capacity = 3)" << endl;_a = (int*)malloc(sizeof(int) * capacity);//要重新开辟空间if (nullptr == _a){perror("malloc申请空间失败!!!");}_capacity = capacity;_top = 0;}//拷贝构造函数Stack(const Stack& stt ) {_a = (int*)malloc(sizeof(int) * stt._capacity);if (_a == nullptr) {perror("malloc");exit(-1);}memcpy(_a, stt._a, sizeof(int) * stt._top);_capacity = stt._capacity;_top = stt._top;}~Stack(){cout << "~Stack()" << endl;free(_a);_capacity = _top = 0;_a = nullptr;}private:int* _a;int _capacity;int _top;};
void Func(Stack stt) {//....
}
int main() {Stack st1;Func(st1);return 0;
}

就会发现是正常运行,如下在这里插入图片描述

		//拷贝构造函数Stack(const Stack& stt ) {_a = (int*)malloc(sizeof(int) * stt._capacity);if (_a == nullptr) {perror("malloc");exit(-1);}memcpy(_a, stt._a, sizeof(int) * stt._top);_capacity = stt._capacity;_top = stt._top;}

通过拷贝构造函数我们可以看出,是重新开辟了一块空间进行拷贝构造,而且我们使用了引用(&)。那么为什么要用引用呢?
下面我们用日期类函数进行演示:

#include<iostream>
using namespace std;
class Date {
public:Date(int year=1, int month=1, int day=1) {_year = year;_month = month;_day = day;}//错误的拷贝构造函数Date(Date d) {_year = d._year;_month = d._month;_day = d._day;}void Print() {cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year ;int _month ;int _day ;
};
int main() {Date d1;d1.Print();Date d2(d1);d2.Print();return 0;
}

我们会发现代码没有办法运行,进行下面的报错
在这里插入图片描述
这是由于当我们d2要对d1进行拷贝构造时发生了以下过程:
规定传值传参都要去调用拷贝构造函数那么,中间就还有临时变量要创建和拷贝,这样一环套一环没有终点。如下:
在这里插入图片描述
综上,所以我们要用引用,直接将d1赋值给d,如下所示:
在这里插入图片描述

#include<iostream>
using namespace std;
class Date {
public:Date(int year=1, int month=1, int day=1) {_year = year;_month = month;_day = day;}//正确的拷贝构造函数Date(Date& d) {_year = d._year;_month = d._month;_day = d._day;}void Print() {cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year ;int _month ;int _day ;
};
int main() {Date d1;d1.Print();Date d2(d1);d2.Print();return 0;
}
3. 若未显式定义,编译器会生成默认的拷贝构造函数。

默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。
注意:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数是一定要写的,否则就是浅拷贝。

所以其实日期类是不用进行我们自己写拷贝构造函数的,因为日期类浅拷贝就够用了,我在上面用日期类进行举例是为了方便我们理解。拷贝构造还是主要用在我开始写的栈类型的程序上。

#include<iostream>
using namespace std;class Stack{public:Stack(size_t capacity = 3){cout << "Stack(size_t capacity = 3)" << endl;_a = (int*)malloc(sizeof(int) * capacity);//要重新开辟空间if (nullptr == _a){perror("malloc申请空间失败!!!");}_capacity = capacity;_top = 0;}//拷贝构造函数Stack(const Stack& stt ) {_a = (int*)malloc(sizeof(int) * stt._capacity);if (_a == nullptr) {perror("malloc");exit(-1);}memcpy(_a, stt._a, sizeof(int) * stt._top);_capacity = stt._capacity;_top = stt._top;}~Stack(){cout << "~Stack()" << endl;free(_a);_capacity = _top = 0;_a = nullptr;}private:int* _a;int _capacity;int _top;};
void Func(Stack stt) {//....
}
int main() {Stack st1;Func(st1);Stack st2(st1);return 0;
}

通过调试上述代码我们发现,它们_a的地址不同,但是_capacity、_top的值是相同的,成功完成了拷贝构造。
在这里插入图片描述
运行后的结果如下:
在这里插入图片描述

4. 拷贝构造函数典型调用场景

使用已存在对象创建新对象
函数参数类型为类类型对象
函数返回值类型为类类型对象

相关文章:

C++的拷贝构造函数

目录 拷贝构造函数一、为什么用拷贝构造二、拷贝构造函数1、概念2、特征1. 拷贝构造函数是构造函数的一个重载形式。2. 拷贝构造函数的参数3. 若未显式定义&#xff0c;编译器会生成默认的拷贝构造函数。4. 拷贝构造函数典型调用场景 拷贝构造函数 一、为什么用拷贝构造 日期…...

【手机端远程连接服务器】安装和配置cpolar+JuiceSSH:实现手机端远程连接服务器

文章目录 1. Linux安装cpolar2. 创建公网SSH连接地址3. JuiceSSH公网远程连接4. 固定连接SSH公网地址5. SSH固定地址连接测试 处于内网的虚拟机如何被外网访问呢?如何手机就能访问虚拟机呢? cpolarJuiceSSH 实现手机端远程连接Linux虚拟机(内网穿透,手机端连接Linux虚拟机) …...

Jupyter Notebook的使用

文章目录 Jupyter Notebook一、Jupyter Notebook是什么&#xff1f;二、使用步骤1.安装Miniconda2.安装启动**Jupyter Notebook**3.一些问题 三、Jupyter Notebook的操作1.更换解释器2.在指定的文件夹中打开3 运行的快捷键 四.报错解决1.画图的时候出现报错2.画图的时候空白3.p…...

vue 使用vue-office预览word、excel,pdf同理

在此&#xff0c;我只使用了docx和excel&#xff0c; pdf我直接使用的iframe进行的展示就不作赘述了 //docx文档预览组件 npm install vue-office/docx//excel文档预览组件 npm install vue-office/excel//pdf文档预览组件 npm install vue-office/pdf如果是vue2.6版本或以下还…...

【Spring Boot 源码学习】RedisAutoConfiguration 详解

Spring Boot 源码学习系列 RedisAutoConfiguration 详解 引言往期内容主要内容1. Spring Data Redis2. RedisAutoConfiguration2.1 加载自动配置组件2.2 过滤自动配置组件2.2.1 涉及注解2.2.2 redisTemplate 方法2.2.3 stringRedisTemplate 方法 总结 引言 上篇博文&#xff0…...

Linux中如何进行粘贴复制

因为CTRLC在Linux中具有特定的含义:终止当前操作 xshell提供了CTRLinsert(复制)/shiftinsert(粘贴) 上述快捷键在Windows中依旧支持,...

多输入多输出 | Matlab实现k-means-LSTM(k均值聚类结合长短期记忆神经网络)多输入多输出组合预测

多输入多输出 | Matlab实现k-means-LSTM&#xff08;k均值聚类结合长短期记忆神经网络&#xff09;多输入多输出组合预测 目录 多输入多输出 | Matlab实现k-means-LSTM&#xff08;k均值聚类结合长短期记忆神经网络&#xff09;多输入多输出组合预测预测效果基本描述程序设计参…...

学习笔记3——JVM基础知识

学习笔记系列开头惯例发布一些寻亲消息 链接&#xff1a;https://baobeihuijia.com/bbhj/contents/3/196593.html JVM&#xff08;Write Once&#xff0c;Run Anywhere&#xff09; 以下是一些学习时有用到的资料&#xff0c;只学习了JVM的基础知识&#xff0c;对JVM整体进…...

图像处理:图片二值化学习,以及代码中如何实现

目录 1、了解下图片二值化的含义 2、进行图像二值化处理的方法 3、如何选择合适的阈值进行二值化 4、实现图片二值化&#xff08;代码&#xff09; &#xff08;1&#xff09;是使用C和OpenCV库实现&#xff1a; &#xff08;2&#xff09;纯C代码实现&#xff0c;不要借…...

如果你点击RabbitMQ Service - start了,但http://localhost:15672/#/还是访问不了,那么请看这篇博客!

RabbitMQ 服务启动失败问题小结&#xff08;Windows环境&#xff09;_rabbitmq启动不了-CSDN博客...

Shell 脚本学习 day01

release node v1 初始版本 #定义备份目录#当前时间#检查备份目录是否存在&#xff0c;不存在需要创建# 查找并备份 .xxx 文件# 提取文件名&#xff08;不包含路径部分&#xff09;# 构建备份文件名# 将查出来的.xxx文件拷贝到备份目录#!/bin/bash # context 备份根目录下所有.…...

esp32 rust linux

官方文档&#xff1a;https://esp-rs.github.io/book/introduction.html 安装 rust curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh 工具 risc&#xff1a; rustup toolchain install nightly --component rust-src # nightly 支持 riscv或使用安装工具同时…...

一文了解Elasticsearch

数据分类 数据按数据结构分类主要有三种&#xff1a;结构化数据、半结构化数据和非结构化数据。 结构化数据 结构化数据具有明确定义数据模型和格式的数据类型。 特点&#xff1a; 数据具有固定的结构和模式。 数据项明确定义数据类型和长度。 适合用于数据查询、过滤和分…...

一篇文章认识【性能测试】

一、 性能测试术语解释 1. 响应时间 响应时间即从应用系统发出请求开始&#xff0c;到客户端接收到最后一个字节数据为止所消耗的时间。响应时间按软件的特点再可以细分&#xff0c;如对于一个 C/S 软件的响应时间可以细分为网络传输时间、应用服务器处理时间、数据库服务器…...

linux环境mysql安装配置踩坑

背景&#xff1a; 最近公司项目希望改造工作流ACTIVITI5.x的源码框架支持大数据量&#xff08;历史表单表数据达到10亿&#xff09;&#xff0c; 方案暂定为 1.使用动态数据源 2.将工作流归档历史数据数据保存到一个库中这里定义为读库&#xff0c; 3.在办办件的数据单独一个库…...

相关性网络图 | 热图中添加显著性

一边学习&#xff0c;一边总结&#xff0c;一边分享&#xff01; 本期教程 写在前面 此图是一位同学看到后&#xff0c;想出的一期教程。 最近&#xff0c;自己的事情比较多&#xff0c;会无暇顾及社群和公众号教程。 1 安装和加载相关的R包 library(ggraph) library(tidy…...

cocosCreator 之 微信小游戏授权设置和调用wxAPI获取用户信息

版本&#xff1a; 3.8.0 语言&#xff1a; TypeScript 环境&#xff1a; Mac 官方文档&#xff1a; 微信官方文档 - 开放能力 微信 API 小游戏环境 在cocosCreator的3.x版本项目开发中&#xff0c;TypeScript最终会被转换为JavaScript语言。 JavaScript的运行时调用的API…...

element ui el-table表格纵向横向滚动条去除并隐藏空白占位列

需求 当table内容列过多时&#xff0c;可通过height属性设置table高度以固定table高度、固定表头&#xff0c;使table内容可以滚动 现在需求是右侧滚动条不好看&#xff0c;需要去除滚动条&#xff0c;并隐藏滚动条所占列的位置 // ----------修改elementui表格的默认样式-…...

防止python进程重复执行

前言 通过保存的进程pid查询上次执行的进程是否退出,决定是否启动新的python进程 代码 pidOption.py import os import psutil pidPath = "saveFile.pid"#写入进程号 def writePid():pid = str(os.getpid())f = open(pidPath, w)f.write(pid...

LV.12 D13 C工程与寄存器封装 学习笔记

一、C语言工程简介 把模板在linux解压出来 代码写在interface.c就可以了。 map.lds是链接脚本文件&#xff08;负责代码的排布&#xff09; include中是头文件&#xff0c;src中是写好的源代码 start.s是启动代码&#xff0c;在interface.c之前运行&#xff0c;把cpu和栈做一…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

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

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

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...