C++之类和对象三

目录

拷贝构造函数

定义铺垫

浅拷贝

深拷贝

总结


拷贝构造函数

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

定义铺垫

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

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

  1.  拷贝构造函数是构造函数的一个重载形式
  2.  拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。
  3.  若未显示定义,系统生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷 贝,这种拷贝我们叫做浅拷贝,或者值拷贝。
  4.  那么编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,我们还需要自己实现吗?当然像 日期类这样的类是没必要的
class Date
{
public:Date(){_year = -1;_month = -1;_day = -1;}Date(int year, int month, int day){_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;cout << &_year << "-" << &_month << "-" << &_day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1(2024, 4, 18);d1.Print();Date d2(d1);d2.Print();return 0;
}

在这里我们给一段代码。

其中要注意这里的拷贝构造是引用传参

我们发现他们的打印结果相同 地址也相同

这就是拷贝函数

浅拷贝

class Date
{
public:Date(){_year = -1;_month = -1;_day = -1;}Date(int year, int month, int day){_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;cout << &_year << "-" << &_month << "-" << &_day << endl;}
private:int _year;int _month;int _day;
};
void func(Date d)
{d.Print();
}
int main()
{Date d1(2024, 4, 18);func(d1);return 0;
}

然后我们在进行调试 

我们会发现当我们的d1初始化完后,我们下一步按F11时,会先进入Date的拷贝构造中,然后再调用func函数

所以

调用func得先传参,自动以类型对象传值传参要调用拷贝构造

当然了我们也可以不去使用拷贝构造

比如使用指针或者使用引用

void func(Date& d)
{d.Print();
}
void func(Date* d)
{d.Print();
}

一个是d1的地址一个是d1的别名

在这里我们还可以继续更改一下代码

Date(const Date& d){this->_year = d._year;this->_month = d._month;this->_day = d._day;}

加上一个const去缩小权限

因为我们只是拷贝构造不需要改变值

这里也是存在this指针的

Date(const Date& d){this->_year = d._year;this->_month = d._month;this->_day = d._day;}

拷贝构造的形式有很多

int main()
{Date d1(2024, 4, 18);Date d2 = d1;Date d3(d2);return 0;
}

这种类似于赋值的形式也是拷贝构造

class Date
{
public:Date(){_year = -1;_month = -1;_day = -1;}Date(int year, int month, int day){_year = year;_month = month;_day = day;}/*Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}*/void Print(){cout << _year << "-" << _month << "-" << _day << endl;cout << &_year << "-" << &_month << "-" << &_day << endl;}
private:int _year;int _month;int _day;
};
void func(Date d)
{d.Print();
}
int main()
{Date d1(2024, 4, 18);Date d2 = d1;Date d3(d2);d2.Print();d3.Print();return 0;
}

我们把我们的拷贝构造给注释掉

然后在进行打印会发现依旧会进行拷贝构造

原因是拷贝构造是默认的成员函数,不写他会进行值的拷贝,简称值拷贝

深拷贝

但如果是栈呢?

struct stack
{
public:int* a;int size;int capacity;void Init(int n = 4){a = (int*)malloc(sizeof(int) * n);if (a == nullptr){perror("malloc fail");return;}//...size = 0;capacity = n;}void Push(int x){a[size++] = x;}
};
int main()
{/*Date d1(2024, 4, 18);Date d2 = d1;Date d3(d2);d2.Print();d3.Print();*/stack st;st.Push(1);st.Push(1);st.Push(1);stack st1 = st;return 0;
}

 我们会发现代码崩溃了

但拷贝是否完成了呢?

拷贝完成了

我们这里也是完成了值拷贝

这里会存在一个大问题

如果只进行了值拷贝,也就是说这两个栈都是使用的同一块内存,如果进行析构的话会进行两次,出现错误,所以只要是存在浅拷贝/值拷贝,就会可能出现一定的错误

所以,浅拷贝的类我们可以进行值拷贝,但如果是深拷贝就需要慎重考虑了

 所以这里怎么办呢?

我们可以在构造函数时进行一定的改进

struct stack
{
public:/*void Init(int n = 4){a = (int*)malloc(sizeof(int) * n);if (a == nullptr){perror("malloc fail");return;}size = 0;capacity = n;}*/void Push(int x){a[size++] = x;}stack(const stack& st){a = (int*)malloc(sizeof(int) * st.capacity);if (a == nullptr){perror("malloc fail");return;}memcpy(a, st.a, sizeof(int) * st.size);size = st.size;capacity = st.capacity;}stack(){a = (int*)malloc(sizeof(int) * capacity);if (a == nullptr){perror("malloc fail");return;};size = capacity = 4;}~stack(){a = nullptr;size = capacity = 0;}
private:int* a = nullptr;int size = 4;int capacity = 4;
};
int main()
{/*Date d1(2024, 4, 18);Date d2 = d1;Date d3(d2);d2.Print();d3.Print();*/stack st1;st1.Push(1);st1.Push(1);st1.Push(1);stack st2 = st1;return 0;
}

这样我们的代码就可以正常运行拷贝构造了

总结

总结一下:

  1. 如果没有管理资源,一般情况下不需要写拷贝构造,默认生成的拷贝构造就可以,如:Date

  2. 如果自定义类型的话,内置类型没有指向资源,也类似默认生成的拷贝构造就可以
  3. 一般情况下,不需要显示写析构函数,就不需要写拷贝构造
  4. 如果内部有指针或者有一些只想资源,需要显示写析构函数,通常就需现实些构造完成深拷贝。如:stack,queue

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

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

相关文章

第十五届蓝桥杯大赛软件赛省赛(Java 大学B组)

蓝桥杯 2024年省赛真题 Java 大学B组 试题 A: 报数游戏试题 B: 类斐波那契循环数试题 C: 分布式队列 在找工作&#xff0c;随便写写&#xff0c;安定下来再把去年国赛题解补上 试题 A: 报数游戏 本题总分&#xff1a; 5 5 5 分 【问题描述】 小蓝和朋友们在玩一个报数游戏。由…

顺丰同城急送API对接(附源码)

一、背景 最近公司让我对接顺丰同城急送的API&#xff0c;讲讲里面需要注意的几点 官方的API文档有些示例代码也不全&#xff0c;具体细节不多说&#xff0c;如果你现在也需要对接他们API&#xff0c;可以参考本篇博客再配合官方文档结合起来看&#xff0c;可以让您再开发的时…

期权小知识科普

期权的交易时间 上交所期权合约的交易时间为每个交易日9:15至9:25、9:30至11:30、13&#xff1a;00至15:00。 其中&#xff0c;9:15至9:25为开盘集合竞价时间&#xff0c;14:57-15:00为收盘集合竞价时间&#xff0c;其余时段为连续竞价时间&#xff0c;交易所规则另有规定的除…

Pytorch-自动微分模块

&#x1f947;接下来我们进入到Pytorch的自动微分模块torch.autograd~ 自动微分模块是PyTorch中用于实现张量自动求导的模块。PyTorch通过torch.autograd模块提供了自动微分的功能&#xff0c;这对于深度学习和优化问题至关重要&#xff0c;因为它可以自动计算梯度&#xff0c…

VUE-列表

VUE-列表 列表功能 如下例子 列表展示 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv&qu…

CorelDRAW Graphics Suite2024最新永久免费版功能强大的图形设计软件

CorelDRAW Graphics Suite是一款功能强大的图形设计软件套件&#xff0c;它提供了丰富的绘图工具、编辑功能和设计资源&#xff0c;适用于从专业设计师到普通用户的广泛群体。以下是CorelDRAW Graphics Suite的一些主要功能特点&#xff1a; 矢量图形设计&#xff1a;CorelDRAW…

Jenkins 流水线多阶段构建

Jenkins流水线配置遇到 无法识别的。需要使用 自定义环境 项。 比如官网的在流水线中使用Docker Started by remote host 172.17.0.1 Obtained Jenkinsfile from git http://10.99.20.51:8082/root/java-devops-demo.git org.codehaus.groovy.control.MultipleCompilationErro…

智慧化赋能园区新未来:探讨智慧园区如何以科技创新为引擎,推动产业转型升级

随着科技的飞速发展&#xff0c;智慧化已成为推动园区产业升级和转型的重要引擎。智慧园区&#xff0c;以其高效、便捷、智能的特性&#xff0c;正逐步改变传统的产业园区模式&#xff0c;为产业发展注入新的活力。本文旨在探讨智慧园区如何以科技创新为引擎&#xff0c;推动产…

成都企业设计图纸加密和文档加密如何进行防泄密保护

企业数据防泄密对企业管理者来说&#xff0c;已经是一个老生常谈的问题了&#xff0c;但是企业图纸外泄一直困扰着企业的管理者&#xff0c;如何对自身企业的图纸进行保护才能做到企业的图纸防泄密呢&#xff1f;现在市场上图纸防泄密主要是采用驱动层透明加密的方式&#xff0…

制作适用于openstack平台的win10镜像

1. 安装准备 从MSDN下载windows 10的镜像虚拟机开启CPU虚拟化的功能。从Fedora 网站下载已签名的 VirtIO 驱动程序 ISO 。 创建15 GB 的 qcow2 镜像&#xff1a;qemu-img create -f qcow2 win10.qcow2 15G 安装必要的软件 yum install qemu-kvm qemu-img virt-manager libvir…

GaN HEMT中短沟道效应的建模

来源&#xff1a;Modeling of Short-Channel Effects in GaN HEMTs&#xff08;TED 20年&#xff09; 摘要 在本文中&#xff0c;我们提出了一种用于估算GaN高电子迁移率晶体管&#xff08;HEMT&#xff09;器件中短沟道效应&#xff08;SCEs&#xff09;的显式和解析的基于电…

常见的分类算法介绍

常见的分类算法主要包括以下几种&#xff0c;它们各自有不同的特点和适用场景&#xff1a; 1. 逻辑回归&#xff08;Logistic Regression&#xff09; - 特点&#xff1a;逻辑回归是一种线性分类算法&#xff0c;通过使用逻辑函数预测概率&#xff0c;然后根据概率决定分类…

算法训练营第45天|70.爬楼梯(进阶)LeetCode 322.零钱兑换 279.完全平方数

70.爬楼梯&#xff08;进阶&#xff09; 题目链接&#xff1a; 70.爬楼梯&#xff08;进阶&#xff09; 代码&#xff1a; #include<iostream> #include<vector> using namespace std; int main(){int n,m;cin>>n>>m;vector<int>dp(n1);dp[0…

【创建型模式】单例模式

一、单例模式概述 单例模式的定义&#xff1a;又叫单件模式&#xff0c;确保一个类只有一个实例&#xff0c;并提供一个全局访问点。&#xff08;对象创建型&#xff09; 要点&#xff1a; 1.某个类只能有一个实例&#xff1b;2.必须自行创建这个实例&#xff1b;3.必须自行向整…

固体矿产资源储量分类GBT17766-2020

1999分类标准采用三轴体系划分资源量与处理&#xff0c;表达复杂、经济意义划分过细、实用性不强 虽然不再采用”三轴“表达方式&#xff0c;但依然考虑地质可靠程度、经济意义、可行性评价 矿产资源勘查&#xff1a;通常依靠地球科学知识&#xff0c;运用地质填图&#xff0…

vue中,为什么data属性是一个函数,而不是一个对象?

vue中&#xff0c;为什么data属性是一个函数&#xff0c;而不是一个对象&#xff1f; vue2中&#xff0c;data是一个函数&#xff0c;而不是一个对象的原因&#xff0c;与组件的复用和独立性有关。 在vue中定义一个组件时&#xff0c;这个组件可能会被多次复用&#xff0c; …

python语言零基础入门——变量与简单数据类型

目录 一、变量 1.创建变量 2.变量的修改 3.变量的命名 &#xff08;1&#xff09;常量 &#xff08;2&#xff09;标识符 &#xff08;3&#xff09;关键字 &#xff08;4&#xff09;命名规则 二、简单数据类型 1.变量的数据类型 2.数据类型 3.整型&#xff08;In…

软考-系统集成项目管理中级--项目人力资源管理(输入输出很重要!!!本章包含案例题,着重复习)

本章历年考题分值统计 本章重点常考知识点汇总清单(掌握部分可直接理解记忆) 1、人力资源管理的过程:(掌握) (1)项目人力资源计划编制:确定与识别项目中的角色、分配项目职责和汇报关系&#xff0c;并记录下来形成书面文件&#xff0c;其中也包括项目人员配备管理计划。…

C语言进阶课程学习记录-第39课 - 程序中的3个基本数据区

C语言进阶课程学习记录-第39课 - 程序中的3个基本数据区 栈实验-栈空间释放后数据无效堆静态存储区实验-静态变量和全局变量小结 本文学习自狄泰软件学院 唐佐林老师的 C语言进阶课程&#xff0c;图片全部来源于课程PPT&#xff0c;仅用于个人学习记录 栈 实验-栈空间释放后数据…

吴恩达机器学习笔记:第 8 周-13 聚类(Clustering)13.1-13.2

目录 第 8 周 13、 聚类(Clustering)13.1 无监督学习&#xff1a;简介 第 8 周 13、 聚类(Clustering) 13.1 无监督学习&#xff1a;简介 在这个视频中&#xff0c;我将开始介绍聚类算法。这将是一个激动人心的时刻&#xff0c;因为这是我们学习的第一个非监督学习算法。我们…