C++的类和对象(四):拷贝构造函数

目录

拷贝构造函数

特性

自定义类型的传值传参和传引用传参对比

赋值运算符重载


拷贝构造函数

基本概念:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在创建一个已存在对象一模一样的新对象时由编译器自动调用

调用格式:类名 新对象(同类对象名)

类中格式: 类名(const 类名& 变量名)

作用:创建一个已存在对象一模一样的新对象

特性

1、拷贝构造函数是构造函数的一个重载形式(重名构成函数重载)

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

#include <iostream>
using namespace std;class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//正确写法:Date(Date& d)//最佳写法:Date(const Date& d)Date(Date d)//错误写法{_year = d._year;_month = d._month;_day = d._day;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2024,3,7);Date d2(d1);return 0;
}

自定义类型的传值传参和传引用传参对比

#include <iostream>
using namespace std;class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Date(Date& d){_year = d._year;_month = d._month;_day = d._day;}
private:int _year;int _month;int _day;
};//传值传参
void func1(Date d)//d是d1的拷贝
{}//传引用传参
void func2(Date& rd)//rd是d1的别名
{}int main()
{Date d1(2024,3,7);func1(d1);func2(d1);return 0;
}

调试过程:20240307_111203-CSDN直播

        在调用func1函数前传参的过程中(d1对象的成员变量的数值会传递给d)会先进入拷贝构造函数中,执行完拷贝构造后才会调用func1函数:

在调用func2函数前传参的过程中不会进入拷贝构造函数,在传参结束后会直接调用func2函数:

这是因为C++规定,将一个对象作为参数传递给函数时(如果参数是按值传递而不是引用)会调用拷贝构造函数,如果我们不额外的写这两个函数来找寻找传值调用和传参调用的区别而是直接将拷贝构造函数写成Date(Date A):

就会造成无限递归,由于我们想要用d1对象中的成员变量的值去初始化d2对象的成员变量的值,在传值传参时d1传递给拷贝构造函数的是一个它值(所有成员变量的值)的临时拷贝,这个值也可以被视为一个新的对象e1,想要做的是初始化这个新的对象然后将初始化的结果带回去,带不带的回去还是一说(传值调用,形参是实参的拷贝,对形参的改变不会影响实参),当我们尝试初始化这个对象时又会调用拷贝构造函数,此时又会生成e1的拷贝,新对象f1......

结论:直接记住拷贝构造函数的格式即可,当你尝试使用传值传参时,编译器会报错

调用函数时先传参后调用  

#include <stdio.h>
int func(int a)
{return a;
}int main()
{func(5);return 0;
}

3、拷贝构造函数记得引用前要加const,const可以很好的保护被引用的对象(d1对象的值不能被d2对象的值初始化

        否则出现原本是想借用拷贝构造函数初始化新对象的成员变量,但是赋值两端的内容写反了,新对象的成员变量(随机值)反而把拷贝构造函数的成员变量初始化成随机值了

d2(d1)看起来只是将对象d1作为实参传递了,但实际上还有一个包含d2对象地址的this指针 

 4、若为显示定义拷贝构造函数,编译器会生成默认的拷贝构造函数,默认拷贝构造函数会对内置类型成员变量会进行值拷贝(将成员变量的字节依照原有的顺序一个一个的拷贝)也叫浅拷贝

#include <iostream>
using namespace std;class Date
{
public:Date(int year = 1900, 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(2024,3,7);Date d2(d1);d1.Print();d2.Print();return 0;
}

5、 拷贝构造函数也是构造函数

#include <iostream>
using namespace std;class Time
{
public:~Time(){cout << "~Time()" << endl;}//强制编译器生成默认构造函数:	Time() = default;Time(const Time& t){cout << "Time(const Time& t)" << endl;_hour = t._hour;_minute = t._minute;_mecond = t._mecond;}
private:int _hour;int _minute;int _mecond;
};class Date
{
public:Date(int year = 1900, 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;//自定义类型Time _t;
};int main()
{Date d1(2024,3,7);Date d2(d1);d1.Print();d2.Print();return 0;
}

由于我们在Time类中提供了拷贝构造函数所以编译器不会生成默认构造函数,对此我们可以使用default关键字强制编译器生成默认构造函数

6、类中没有涉及资源申请时,拷贝构造函数是否写都可以,一旦涉及资源申请,则拷贝构造函数一定要写否则就是浅拷贝

#include <iostream>
using namespace std;
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对象要用s1对象的成员变量进行初始化,Stakc类没有显示定义拷贝构造函数,编译器会生成一份默认的拷贝构造函数,默认拷贝构造函数是按值拷贝的,即将s1中的内容原封不动的拷贝到s2中,对于_size和_capacity没问题,但是_array存放的可是s1在堆上开辟的空间的地址,此时将该地址的值也原封不动的传递给了s2的_array,此时s1和s2对象的_array指向同一片空间,当main函数结束时,s2先销毁,s2销毁时调用析构函数释放掉申请的空间,由于s1不知道,所以会将该空间再次释放,同一块内存空间的多次释放肯定会造成程序崩溃

因此对于申请了空间资源的类我们要进行深拷贝:

#include <iostream>
using namespace std;
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(const Stack& s){DataType* tmp = (DataType*)malloc(s._capacity * (sizeof(DataType)));if(tmp == nullptr){perror("malloc fail");exit(-1);}memcpy(tmp, s._array, sizeof(DataType) * s._size);_array = tmp;_size = s._size;_capacity = s._capacity;}//析构函数~Stack(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}
private:DataType* _array;size_t _size;size_t _capacity;
};int main()
{Stack s1;Stack s2(s1);return 0;
}

~over~

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

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

相关文章

数据结构:AVL树

目录 1、AVL树的概念 2、二叉搜索树的功能与实现 1、AVL树节点定义 2、AVL树的插入 3、AVL树的旋转操作 1、左旋 2、右旋 3、左右旋 4、右左旋 3、AVL树完整代码实现 1、AVL树的概念 在前面的文章中&#xff0c;我们学过了二叉搜索树&#xff0c;二叉搜索树虽可以缩短查…

勾股定理的七种经典证明

据说勾股定理约有500种证明方法&#xff0c;下面介绍几种经典的证明方法。 一、切割重拼法。 顾名思义&#xff0c;就是将图形切割成其他形式的图形&#xff0c;然后通过拼图转换为另一种图形&#xff0c;这个过程中图形的面积是不变的。 “赵爽弦图”是这种方法的经典应用&…

Android视角看鸿蒙第三课(module.json中的各字段含义之nametype)

Android视角看鸿蒙第三课(module.json中的各字段含义) 前言 上篇文章我们试图找到鸿蒙app的程序入口&#xff0c;确定了在鸿蒙工程中,由AppScope下的app.json5负责应用程序的图标及名称,由entry->src->main-module.json5负责桌面图标及名称的展示。 AppScope下的app.js…

使用Kali搭建钓鱼网站教程

一、前言 使用kali工具一分钟制作出和目标网站一模一样的钓鱼网站。目标用户使用钓鱼网站登录自己的账号&#xff0c;账号密码将被自动劫持。 二、钓鱼网站的制作过程 1.在虚拟机VMvare中登录kali linux 2.准备一个目标网址 3.在kail中搜索使用工具 4.在弹出的选项中选择第一…

【JavaEE初阶】 JVM简介

文章目录 &#x1f38d;前言&#x1f343;JVM发展史&#x1f6a9;Sun Classic VM&#x1f6a9;Exact VM&#x1f6a9;HotSpot VM&#x1f6a9;JRockit&#x1f6a9;J9 JVM&#x1f6a9;Taobao JVM&#xff08;国产研发&#xff09; &#x1f340;JVM 运行流程⭕总结 &#x1f3…

基于毕奥-萨伐尔定律的交流电机的4极旋转磁场matlab模拟与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于毕奥-萨伐尔定律的交流电机的4极旋转磁场&#xff0c;对比不同定子半径&#xff0c;对比2级旋转磁场。 2.系统仿真结果 3.核心程序与模型 版本&#xff1a;MATLAB2022a…

RK3568平台 USB数据包的收发格式

一.USB硬件拓扑结构 compound device &#xff1a;多个设备组合起来&#xff0c;通过HUB跟Host相连composite device &#xff1a;一个物理设备有多个逻辑设备(multiple interfaces) 在软件开发过程中&#xff0c;我们可以忽略Hub的存在&#xff0c;硬件拓扑图简化如下&#x…

【开源物联网平台】使用MQTT.fx模拟设备接入FastBee物联网平台

​&#x1f308; 个人主页&#xff1a;帐篷Li &#x1f525; 系列专栏&#xff1a;FastBee物联网开源项目 &#x1f4aa;&#x1f3fb; 专注于简单&#xff0c;易用&#xff0c;可拓展&#xff0c;低成本商业化的AIOT物联网解决方案 目录 一、接入步骤 1.1 创建产品&#xff…

9款世界级垂直领域软件架构师Visio平替作图工具!

1 LucidChart 一个基于HTML5的在线流程图绘制和协作应用平台&#xff0c;用户可以通过它方便快速的实现流程图表的绘制&#xff0c;同时还可以实现与他人进行实时的流程图绘制和修改功能&#xff0c;对需要群组协作功能的团队来说&#xff0c;这点非常方便。 由于LucidChart是…

VM内存结构和垃圾回收机制

引言 在计算机科学中&#xff0c;虚拟机&#xff08;VM&#xff09;是一个重要的概念&#xff0c;它允许程序在硬件平台之上运行。虚拟机模拟真实机器的行为&#xff0c;为程序提供了一个独立的运行环境。本文将深入探讨VM的内存结构和垃圾回收机制&#xff0c;以帮助读者更好…

图形系统开发实战课程:进阶篇(上)——10.应用实例:交通路网

图形开发学院&#xff5c;GraphAnyWhere 课程名称&#xff1a;图形系统开发实战课程&#xff1a;进阶篇(上)课程章节&#xff1a;“图形样式”原文地址&#xff1a;https://www.graphanywhere.com/graph/advanced/2-10.html 第十章 应用实例&#xff1a;交通路网 \quad 在前面几…

基于springboot精品在线试题库系统论文

摘 要 使用旧方法对作业管理信息进行系统化管理已经不再让人们信赖了&#xff0c;把现在的网络信息技术运用在作业管理信息的管理上面可以解决许多信息管理上面的难题&#xff0c;比如处理数据时间很长&#xff0c;数据存在错误不能及时纠正等问题。这次开发的精品在线试题库系…

python爬虫(2)

继上节 查看数组维数 可以使用数组的ndim属性 代码示例如下&#xff1a; import numpy as np c np.random.randint(1,9,5) print(c.ndim) 结果如下&#xff1a; 当然这些也可以结合前面的各种用法来使用 1、选取数组元素 &#xff08;1&#xff09;一维数组的元素…

线程池不香了? 结构化并发才是王道!

我们先定义获取用户信息任务&#xff1a; 再定义获取订单信息任务&#xff1a; 然后再构造线程池并执行任务&#xff1a; 输出结果为&#xff1a; 看上去一切都刚刚好&#xff0c;但是&#xff0c;如果获取订单信息时出错了&#xff0c;此时会是什么现象呢&#xff1f;修改获取…

外包干了一周,技术明显倒退。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;2019年我通过校招踏入了南京一家软件公司&#xff0c;开始了我的职业生涯。那时的我&#xff0c;满怀热血和憧憬&#xff0c;期待着在这个行业中闯出一片天地。然而&#xff0c;随着时间的推移&#xff0c;我发现自己逐渐陷入…

BUUCTF-Misc2

wireshark1 1.打开附件 发现是流量包&#xff0c;放到Wireshark中分析 2.过滤 根据题目的提示寻找管理员登录的网站&#xff0c;从中获取密码 用http.request.methodPOST&#xff0c;过滤当前的 HTTP 请求为 POST 方法 3.查找 双击过滤后的流量包&#xff0c;查找管理员密码…

TCP/IP模型中网络层和网络接口层的区别 通俗解释

问题 TCP/IP模型中的网络层和网络接口层有什么区别&#xff0c;或者说 ip地址和mac地址有什么区别&#xff0c;通过ip不就能找到要发送的设备了吗 为什么还需要mac地址用简单的语言来解释一下。 TCP/IP模型中的网络层和网络接口层主要的区别在于它们处理的信息和功能不同&…

Self-evolve——基于大语言模型的代码演进框架

导语 本研究提出了一个名为Self-evolve的框架&#xff0c;它旨在通过大型语言模型&#xff08;LLMs&#xff09;实现代码生成的进化。这一框架在Text-to-Code任务中引入了一种全新的处理流程&#xff0c;以提高LLMs在代码生成方面的效率和准确性。在之前&#xff0c;尽管LLMs在…

2024【问题解决】Github 2024无法克隆git clone自从签了2F2安全协议之后

项目场景:ping通Github但没法clone–502 问题描述 提示:ping通Github但没法clone--502: 例如:git clone https://gitclone.com/l.git/*** $ git clone https://github.com/darrenpig/Yocto Cloning into Yocto_tutorial... fatal: unable to access https://gitclone.co…

从仓储管理看3C电子行业智慧物流的优势

仓储管理是智慧物流的重要组成部分。通过引入自动化、智能化的仓储管理系统&#xff0c;3C电子企业可以实现库存的精准管理、快速分拣和高效配送。这不仅减少了库存成本&#xff0c;还大大提高了运营效率和市场响应速度。 传统的仓储管理依赖于人工操作和纸质文档记录&#xff…