C++ 深拷贝和浅拷贝

虽然我们知道了拷贝构造函数,但是大多数简单程序中都不需要特别编写拷贝构造函数,隐含的拷贝构造函数足以实现对象间数据元素的一一对应复制。但是隐含的拷贝构造函数并不总是适用的,因为它完成的只是浅拷贝。

1.浅拷贝

【例】对象的浅拷贝

class Point
{
public:
	Point() :x(0), y(0)
	{
		cout << "调用默认构造函数" << endl;//数组元素的地址

	}

	Point(int x, int y) :x(x), y(y)
	{
		cout << "调用构造函数" << endl;
	}
	~Point()
	{
		cout << "调用析构函数" << endl;
	}
	int getX() 
	{
		return x;
	}
	int getY() 
	{
		return y;
	}
	void move(int newX, int newY)
	{
		x = newX;
		y = newY;
		cout << "(" << x << "," << y << ")" << endl;//对应数组元素的地址
	}
private:
	int x, y;
};

//动态数组类
class Arr
{
public:
	Arr(int size) :size(size)
	{
		points = new Point[size];

	}
	~Arr()
	{
		cout << "删除对象:" << endl;
		delete[]points;
	}
	//获得下标为index的数组元素
	Point& element(int index)
	{
		assert(index >= 0 && index < size);//如果数组下标越界,程序中止
		return points[index];
	}
private:
	Point* points;//指向动态数组的首地址
	int size;//数组大小
};

int main()
{
	int count;
	cout << "请输入点的个数:";
	cin >> count;
	Arr parr1(count);
	parr1.element(0).move(1, 2);
	parr1.element(1).move(2, 3);
	parr1.element(2).move(3, 4);


	Arr parr2(parr1);

	cout << "从parr1拷贝过来的点:" << endl;
	cout << "parr2的第一个元素:" << "(" << parr2.element(0).getX() << "," << parr2.element(0).getY() << ")" << endl;
	cout << "parr2的第二个元素:" << "(" << parr2.element(1).getX() << "," << parr2.element(1).getY() << ")" << endl;
	cout << "parr2的第三个元素:" << "(" << parr2.element(2).getX() << "," << parr2.element(2).getY() << ")" << endl;

	cout << "更新parr1的内容:" << endl;
	parr1.element(0).move(10, 20);
	parr1.element(1).move(20, 30);
	parr1.element(2).move(30, 40);

	cout << "更新parr1的内容之后parr2的内容:" << endl;
	cout << "parr2的第一个元素:" << "(" << parr2.element(0).getX() << "," << parr2.element(0).getY() << ")" << endl;
	cout << "parr2的第二个元素:" << "(" << parr2.element(1).getX() << "," << parr2.element(1).getY() << ")" << endl;
	cout << "parr2的第三个元素:" << "(" << parr2.element(2).getX() << "," << parr2.element(2).getY() << ")" << endl;

	return 0;

}

运行结果:
在这里插入图片描述
结果分析:

程序中parr2的内容是从parr1中拷贝过来的,它们的初始状态是一样的,但是当程序通过move函数更新parr1中的第一组点之后,parr2中的第二组点也被更新到了同样的位置。这就说明两组点之间存在着某种必然的联系,而这种联系并不是我们所期望的。

这里建立对象parr2时调用的是隐含的默认拷贝构造函数,实现对应数据项的直接拷贝。如下图所示:
在这里插入图片描述
当程序中更新parr1中的点时,也影响到了parr2。这种效果就是“浅拷贝”。

浅拷贝还有很大的弊病,在程序结束之前parr1和parr2的析构函数会被自动调用,在把理想的结果输出完成后会连续不停止地一直输出“调用析构函数”,动态内存的分配空间会被释放。由于两个对象共用了一块内存空间,因此该空间被释放了两次,于是导致运行错误。解决这一问题的方法是编写拷贝构造函数,实现“深拷贝”。

1.浅拷贝

【例】对象的深拷贝

class Point
{
public:
	Point() :x(0), y(0)
	{
		cout << "调用默认构造函数" << endl;//数组元素的地址

	}

	Point(int x, int y) :x(x), y(y)
	{
		cout << "调用构造函数" << endl;
	}
	~Point()
	{
		cout << "调用析构函数" << endl;
	}
	int getX()
	{
		return x;
	}
	int getY()
	{
		return y;
	}
	void move(int newX, int newY)
	{
		x = newX;
		y = newY;
		cout << "(" << x << "," << y << ")" << endl;//对应数组元素的地址
	}
private:
	int x, y;
};

//动态数组类
class Arr
{
public:
	Arr(const Arr& v);
	Arr(int size) :size(size)
	{
		points = new Point[size];

	}
	~Arr()
	{
		cout << "删除对象:" << endl;
		delete[]points;
	}
	//获得下标为index的数组元素
	Point& element(int index)
	{
		assert(index >= 0 && index < size);//如果数组下标越界,程序中止
		return points[index];
	}
private:
	Point* points;//指向动态数组的首地址
	int size;//数组大小
};

Arr::Arr(const Arr& v)
{
	size = v.size;
	points = new Point[size];
	for (int i = 0; i < size; i++)
	{
		points[i] = v.points[i];
	}
}
int main()
{
	int count;
	cout << "请输入点的个数:";
	cin >> count;
	Arr parr1(count);
	parr1.element(0).move(1, 2);
	parr1.element(1).move(2, 3);
	parr1.element(2).move(3, 4);


	Arr parr2(parr1);

	cout << "从parr1拷贝到parr2的点:" << endl;
	cout << "parr2的第一个元素:" << "(" << parr2.element(0).getX() << "," << parr2.element(0).getY() << ")" << endl;
	cout << "parr2的第二个元素:" << "(" << parr2.element(1).getX() << "," << parr2.element(1).getY() << ")" << endl;
	cout << "parr2的第三个元素:" << "(" << parr2.element(2).getX() << "," << parr2.element(2).getY() << ")" << endl;

	cout << "更新parr1的内容:" << endl;
	parr1.element(0).move(10, 20);
	parr1.element(1).move(20, 30);
	parr1.element(2).move(30, 40);

	cout << "更新parr1的内容之后parr2的内容:" << endl;
	cout << "parr2的第一个元素:" << "(" << parr2.element(0).getX() << "," << parr2.element(0).getY() << ")" << endl;
	cout << "parr2的第二个元素:" << "(" << parr2.element(1).getX() << "," << parr2.element(1).getY() << ")" << endl;
	cout << "parr2的第三个元素:" << "(" << parr2.element(2).getX() << "," << parr2.element(2).getY() << ")" << endl;

	return 0;

}

运行结果:
在这里插入图片描述
结果分析:

从这次的运行结果可以看出,程序实现的是深拷贝:更新parr1中的点不在影响parr2中的内粗空间,也不再引起错误。深拷贝的过程如图所示:
在这里插入图片描述

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

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

相关文章

面试热题(打家窃舍)

一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响小偷偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报警。 给定一个代表每个房屋存放金额的非负…

通话降噪算法在手机和IOT设备上的应用和挑战

随着电子产品的升级换代&#xff0c;用户对通话质量的要求也越来越高。通话降噪算法对通话质量起到了关键核心的作用。计算资源的提升使得深度学习模型在便携式的低功耗芯片上面跑起来了&#xff0c;器件成本降低让IoT设备开始使用骨导传感器&#xff0c;&#xff0c;那怎么样才…

Python接口自动化-requests模块之post请求

一、源码解析 def post(url, dataNone, jsonNone, **kwargs):r"""Sends a POST request.:param url: URL for the new :class:Request object.:param data: (optional) Dictionary, list of tuples, bytes, or file-likeobject to send in the body of the :cla…

【MySQL】学习汇总(完整思维导图)

用心打造超详细MySQL基础学习教程,文末附系列完整思维导图 内容导航 新手村 SQL入门(一)常见函数使用(二)约束(三)多表查询(四)事务(五) 进阶路 存储引擎(六) SQL性能分析 (七) 索引 (八) SQL优化(九) 视图(十) 存储过程(十一) 触发器(十二) 锁(十三) MySQL管理(十四)…

SpringBoot3---核心特性---2、Web开发I

星光下的赶路人star的个人主页 如果我们总是等待绝对的一切就绪&#xff0c;那我们将永远无法开始 文章目录 1、WebMvcAutoConfiguration1.1 生效条件1.2 效果1.3 WebMvcConfigure接口1.4 静态资源规则代码1.5 EnableWebMvcConfiguration源码1.6 为什么容器中放一个WebMvcConfi…

Flask项目打包为exe(附带项目资源,静态文件)

1.在项目根目录创建my_app.spec文件&#xff0c;内容如下&#xff1a; # -*- mode: python ; coding: utf-8 -*-block_cipher Nonea Analysis([server.py], # flask入口pathex[],binaries[], datas[("E:/**/templates","/templates"),("E:/**/s…

(7.28-8.3)【大数据新闻速递】《数字孪生工业软件白皮书》、《中国绿色算力发展研究报告》发布;华为ChatGPT要来了

【数字孪生工业软件白皮书&#xff08;2023&#xff09;】 近日&#xff0c;第七届数字孪生与智能制造服务学术会议成功举行&#xff0c;2023《数字孪生工业软件白皮书》在会上正式发布。《白皮书》在《Digital Twin》国际期刊专家顾问委员会指导下&#xff0c;由国家重点研发计…

物理量时空属性内禀律

一、物理量时空属性内禀律&#xff1a; 1、物理量具有内在的时空属性&#xff0c;对所有表达式具有时空强制性。 2、物理量时空属性的计算等级较表达式低1个数学等级。 二、物理量时空属性的表示&#xff1a; 空间直线L的时空属性表示为&#xff1a; d(L)(1s,0t) &#xff…

Spring 事务详解(注解方式)

目 录 序言 1、编程式事务 2、配置声明式事务 2.1 基于TransactionProxyFactoryBean的方式&#xff08;不常用&#xff0c;因为要为每一个类配置TransactionProxyFactoryBean&#xff09; 2.2 基于AspectJ的XML方式&#xff08;常用&#xff0c;可配置在某些类下的所有子…

「从零入门推荐系统」22:chatGPT、大模型在推荐系统中的应用

作者 | gongyouliu 编辑 | gongyouliu 提示&#xff1a;全文2.5万字&#xff0c;预计阅读时长2小时&#xff0c;可以先收藏再慢慢阅读。 我们在上一章介绍了chatGPT、大模型的基本概念、核心技术原理等基础知识&#xff0c;有了这些背景知识的铺垫&#xff0c;下面我们来介绍ch…

使用tinyxml解析和修改XML文件

首先要清楚XML文件包含哪些元素&#xff1a; 他是由元素、文本或者两者混合物组成。元素可以拥有属性&#xff0c;元素是指从开始标签到结束标签的部分。 <?xml version"1.0" encoding"UTF-8" ?> <books><book id"1001">&…

day50-springboot+ajax分页

分页依赖&#xff1a; <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.0.0</version> </dependency> 配置&#xff1a; …

【100天精通python】Day23:正则表达式,基本语法与re模块详解示例

目录 专栏导读 1 正则表达式概述 2 正则表达式语法 2.1 正则表达式语法元素 2.2 正则表达式的分组操作 3 re 模块详解与示例 4 正则表达式修饰符 专栏导读 专栏订阅地址&#xff1a;https://blog.csdn.net/qq_35831906/category_12375510.html 1 正则表达式概述 python 的…

苹果电脑第三方应用程序卸载工具CleanMyMacX4.14

CleanMyMacX&#xff0c;这是一款可以帮助你快速识别并卸载电脑上的多个应用程序的第三方工具&#xff0c;省去了逐个卸载的繁琐步骤。 我们首先要到下载CleanMyMacX&#xff0c; CleanMyMac X全新版下载如下: https://wm.makeding.com/iclk/?zoneid49983 然后&#xff0c…

大数据Flink(五十五):Flink架构体系

文章目录 Flink架构体系 一、 Flink中的重要角色 二、Flink数据流编程模型 三、Libraries支持

从 TCP/IP 到 CCIP:Chainlink 与合约的互联网

未来已来。通过链上金融重塑资本市场预计将影响全球价值 8.67 万亿美元的资产的使用方式。 Chainlink 的跨链互操作性协议&#xff08;CCIP&#xff09;将会这一转型过程中发挥重要作用&#xff0c;这是区块链连接性和互操作性的突破&#xff0c;使得 DeFi 应用可以通过单一界…

前端实习day20

今天解决了不少bug&#xff0c;成就感满满&#xff0c;有几个问题困扰了我很久&#xff0c;我查阅了很多博客&#xff0c;终于找到解决思路&#xff0c;顺利解决&#xff0c;这里记录一下解决思路。 1、在通过this.$refs.layoutSide.style设置<a-layout-sider>的宽度时&…

Opencv-C++笔记 (14) : 霍夫变换(直线、圆)

文章目录 一、霍夫变换-直线1.1霍夫变换-直线 原理详解 二、霍夫圆检测 一、霍夫变换-直线 Hough Line Transform用来做直线检测 前提条件 – 边缘检测已经完成 1、平面空间&#xff08;x,y&#xff09;到极坐标空间转换&#xff1b; 2、对极坐标进行变换&#xff0c;转化为…

服务器时钟同步

服务器时钟同步 文章目录 服务器时钟同步背景windows时钟同步Linux机器上的时钟同步Centos时钟同步Ubuntu系统时钟同步 查看是否同步的命令 背景 运维&#xff0c;XXX服务器慢了2秒&#xff0c;导致XXX业务没有正常执行&#xff0c;请立即排查为啥会有时钟不同步的问题。 首先…

ubuntu22安装如何安装window软件(.exe)

ubuntu未提供相应程序安装包&#xff0c;如何使用的ubuntu22.04 安装window提供的exe程序呢&#xff1f; 这里我了解有两种方案&#xff1a; 使用模拟器进行window程序的运行&#xff0c;但是肯定会有相应的性能损耗如&#xff08;wine&#xff09;在linux上运行virtualbox或…