深层次理解拷贝构造函数

1.1 拷贝构造概念

在现实生活中,可能存在一个与你一样的自己,我们称其为双胞胎。

那在创建对象时,可否创建一个与已存在对象一某一样的新对象呢?

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

1.2 特征

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

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

  2. 拷贝构造函数的参数只有一个必须是类类型对象的引用,使用传值方式编译器直接报错

因为会引发无穷递归调用。

为什么拷贝构造函数不能用传值传参?因为c++规定自定义类型都要调用拷贝构造函数,这样子调用自己,会造成无穷递归。

class Date
{
public:
 Date(int year = 1900, int month = 1, int day = 1)
 {
 _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 d3 = d1;//拷贝构造
 return 0;
}

image-20240311140438949.png

// 传值传参
// 内置类型,编译器可以直接拷贝
// 自定义类型的拷贝,需要调用拷贝构造
void Func1(Date d)//这个是自定义类型,需要调用拷贝构造函数, 引发无限递归
{

}

// 传引用传参
void Func2(Date& d)//引用是别名,直接拷贝
{

}

void Func3(Date* d)//这个是指针,也是直接拷贝
{

}

int main()
{
	Date d1(2023, 2, 3);
	Date d2(d1);
	Date d3 = d1;

	//Date d4(&d1);
	//Date d5 = &d1;

	Func1(d1);
	Func2(d1);
	Func3(&d1);

	return 0;
}

const 是权限减小,为了防止程序员误修改了d1。

  1. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按

字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。

深拷贝就是不是单纯的复制,还把malloc开辟的空间也另外开辟。

c语言中结构体传参都是传地址,一旦是传值传参,就是浅拷贝,有可能会出现bug,因为如果传了malloc开辟的地址,结构体传过来修改了,就可能改了原来的结构体。这是c语言的bug。

class Time
{
public:
 Time()
 {
 _hour = 1;
 _minute = 1;
 _second = 1;
     }
 Time(const Time& t)
 {
 _hour = t._hour;
 _minute = t._minute;
 _second = t._second;
 cout << "Time::Time(const Time&)" << endl;
 }
private:
 int _hour;
 int _minute;
 int _second;
};
class Date
{
private:
 // 基本类型(内置类型)
 int _year = 1970;
 int _month = 1;
 int _day = 1;
 // 自定义类型
 Time _t;
};
int main()
{
 Date d1;
    
    // 用已经存在的d1拷贝构造d2,此处会调用Date类的拷贝构造函数
    // 但Date类并没有显式定义拷贝构造函数,则编译器会给Date类生成一个默认的拷贝构
造函数
 Date d2(d1);
 return 0;
}

注意:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定

义类型是调用其拷贝构造函数完成拷贝的。

  1. 编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,还需要自己显式实现吗?

当然像日期类这样的类是没必要的。那么下面的类呢?验证一下试试?

// 这里会发现下面的程序会崩溃掉?这里就需要我们以后讲的深拷贝去解决。
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;
}

image-20240311140558951.png

注意:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请 时,则拷贝构造函数是一定要写的,否则就是浅拷贝。

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

使用已存在对象创建新对象

函数参数类型为类类型对象

函数返回值类型为类类型对象

class Date
{
public:
 Date(int year, int minute, int day)
 {
 cout << "Date(int,int,int):" << this << endl;
 }
 Date(const Date& d)
 {
 cout << "Date(const Date& d):" << this << endl;
 }
 ~Date()
 {
 cout << "~Date():" << this << endl;
 }
private:
 int _year;
 int _month;
 int _day;
};
Date Test(Date d)
{
 Date temp(d);
 return temp;
}
int main()
{
 Date d1(2022,1,13);
 Test(d1);
 return 0;
}

image-20240311140713264.png

为了提高程序效率,一般对象传参时,尽量使用引用类型,返回时根据实际场景,能用引用尽量使用引用。

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

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

相关文章

提面 | 面试抽题

学习到更新日期面试抽题-1.2案例分析的思维本质2024-3-23 1提面抽屉论述问题的分类 1.1案例分析占总论 1.2案例分析的思维本质

权限提升-Windows权限提升篇溢出漏洞土豆家族通杀全系补丁对比EXP筛选

知识点 1、Web到Win-系统提权-土豆家族 2、Web到Win-系统提权-人工操作 章节点&#xff1a; 1、Web权限提升及转移 2、系统权限提升及转移 3、宿主权限提升及转移 4、域控权限提升及转移 基础点 0、为什么我们要学习权限提升转移技术&#xff1a; 简单来说就是达到目的过程…

IMU状态预积分的定义

IMU状态预积分的定义 IMU状态预积分的定义 在ESKF中&#xff0c;将两个GNSS观测之间的IMU数据进行积分&#xff0c;作为ESKF的预测过程。 这种做法把IMU数据看成某种一次性的使用方式&#xff1a;将它们积分到当前估计值上&#xff0c;然后用观测数据更新当时的估计值。 这种…

LeetCode每日一题——统计桌面上的不同数字

统计桌面上的不同数字OJ链接&#xff1a;2549. 统计桌面上的不同数字 - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 思路&#xff1a; 这是一个很简单的数学问题&#xff1a; 当n 5时&#xff0c;因为n % 4 1&#xff0c;所以下一天4一定会被放上桌面 当n 4…

Python制作数据可视化大屏

&#x1f349;CSDN小墨&晓末:https://blog.csdn.net/jd1813346972 个人介绍: 研一&#xff5c;统计学&#xff5c;干货分享          擅长Python、Matlab、R等主流编程软件          累计十余项国家级比赛奖项&#xff0c;参与研究经费10w、40w级横向 文…

springcloud+nacos服务注册与发现

快速开始 | Spring Cloud Alibaba 参考官方快速开始教程写的&#xff0c;主要注意引用的包是否正确。 这里是用的2022.0.0.0-RC2版本的springCloud&#xff0c;所以需要安装jdk21&#xff0c;参考上一个文章自行安装。 nacos-config实现配置中心功能-CSDN博客 将nacos-conf…

vue3对openlayers使用(加高德,天地图图层)

OpenLayers认识 WebGIS四大框架&#xff1a; Leaflet、OpenLayers、Mapbox、Cesium OpenLayers 是一个强大的开源 JavaScript 地图库&#xff0c;专注于提供可嵌入网页的交互式地图体验。作为一款地理信息系统&#xff08;GIS&#xff09;的前端开发工具&#xff0c;OpenLaye…

微软Microsoft Surface Go 2

1个小玩具 Microsoft Surface Go 2的评测结果出炉&#xff01;它是目前最好的中端Windows 二合一笔记本平板。 外形简洁小巧&#xff0c;工作娱乐两不误。 它有多个版本。 我们测试的是配备8GB Ram和128GB SSD的Pentium 4425Y处理器&#xff08;第8代&#xff09;的型号。 S…

OpenCV学习笔记(十一)——利用Sobel算子计算梯度

Sobel算子是基于一阶导数的离散差分算子&#xff0c;其中Sobel对于像素值的变化是十分敏感的&#xff0c;在进行边缘检测的时候&#xff0c;Sobel算子常用于对周围像素的重要性进行检测。 Sobel算子包括检验水平方向的算子和检测竖直方向的算子 计算机梯度值的操作如下&#x…

Dr4g0n

信息收集 # nmap -sn 192.168.56.0/24 -oN live.nmap Starting Nmap 7.94 ( https://nmap.org ) at 2024-03-04 08:52 CST Nmap scan report for 192.168.56.2 Host is up (0.00012s latency). MAC Address: 00:50:56:FE:B1:6F (VMware) Nmap scan report …

Spring Boot从入门到实战

课程介绍 本课程从SpringBoot的最基础的安装、配置开始到SpringBoot的日志管理、Web业务开发、数据存储、数据缓存&#xff0c;安全控制及相关企业级应用&#xff0c;全程案例贯穿&#xff0c;案例每一步的都会讲解实现思路&#xff0c;全程手敲代码实现。让你不仅能够掌Sprin…

JavaEE-文件操作和IO

我们先来认识狭义上的⽂件(file)。针对硬盘这种持久化存储的I/O设备&#xff0c;当我们想要进⾏数据保存时&#xff0c;往往不是保存成⼀个整体&#xff0c;⽽是独⽴成⼀个个的单位进⾏保存&#xff0c;这个独⽴的单位就被抽象成⽂件的概念&#xff0c;就类似办公桌上的⼀份份真…

鸿蒙Harmony应用开发—ArkTS-枚举说明

说明&#xff1a; 本模块首批接口从API version 7开始支持&#xff0c;后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 Color 从API version 9开始&#xff0c;该接口支持在ArkTS卡片中使用。 颜色名称颜色值颜色示意Black0x000000 Blue0x0000ff Brown…

【LAMMPS学习】三、构建LAMMPS(7)具有额外构建选项的软件包

3. 构建 LAMMPS 3.7.具有额外构建选项的软件包 当使用某些包进行构建时&#xff0c;除了Build_package页面上描述的步骤之外&#xff0c;可能还需要额外的步骤。 ​ 对于CMake构建&#xff0c;可能有额外的可选或必需的变量要设置。对于使用make进行构建&#xff0c;可能需…

探索 Flutter 中的 NavigationRail:使用详解

1. 介绍 在 Flutter 中&#xff0c;NavigationRail 是一个垂直的导航栏组件&#xff0c;用于在应用程序中提供导航功能。它通常用于更大屏幕空间的设备&#xff0c;如平板电脑和桌面应用程序。NavigationRail 提供了一种直观的方式来浏览应用程序的不同部分&#xff0c;并允许…

适合马犬吃的狗粮有哪些?

亲爱的朋友们&#xff0c;你们是不是也在为家里的马犬挑选合适的狗粮而犯愁呢&#xff1f;&#x1f436;&#x1f35a; 今天&#xff0c;我就来和大家分享一下适合马犬吃的狗粮有哪些&#xff0c;以及为什么我要特别推荐福派斯鲜肉无谷狗粮。 首先&#xff0c;我们得了解马犬的…

深入理解Redis的Sentinel机制

Sentinel简述 Sentinel为了解决什么问题&#xff1f; Sentinel&#xff08;哨岗、哨兵&#xff09;是Redis的高可用性&#xff08;high availability&#xff09;解决方案。 我们知道Redis 的主从复制模式可以将主节点的数据改变同步给从节点&#xff0c;这样从节点就可以起…

c语言——通讯录(文件版)

大家好我是小锋&#xff0c;今天我们来实现一个通讯录 准备工作 为了让我们的代码具有条理我们要建立三个文件一个文件用来放头文件一个文件用来放函数的实现&#xff0c;一个文件用来实现通讯录的基本逻辑。 然后我们其他的.c文件要使用头文件时我们要用# include<tongxu…

一笔画--PTA

文章目录 题目描述思路AC代码 题目描述 输入样例1 3 2 1 2 2 3 输出样例1 Y输入样例2 4 3 1 2 1 3 1 4 输出样例2 N输入样例3 1 0 输出样例3 Y思路 dfs 、欧拉通路、欧拉回路的判定 前导知识 欧拉通路、欧拉回路、欧拉图 无向图&#xff1a; ①设G是连通无向图&#xff0c;则称…

pycharm免费下载安装教程

pycharm下载地址 Download PyCharm: The Python IDE for data science and web development by JetBrains 1.进入官网之后可以下拉到最底下&#xff0c;可以设置一下所属地是中国大陆&#xff08;China Mainland)&#xff0c;这样在安装的时候展示的就是中文。 2.设置好语言之…