C++ 深拷贝和浅拷贝

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

1.浅拷贝

【例】对象的浅拷贝

cpp 复制代码
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.浅拷贝

【例】对象的深拷贝

cpp 复制代码
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中的内粗空间,也不再引起错误。深拷贝的过程如图所示:

相关推荐
励志的小陈6 小时前
贪吃蛇(C语言实现,API)
c语言·开发语言
Makoto_Kimur6 小时前
java开发面试-AI Coding速成
java·开发语言
laowangpython6 小时前
Gurobi求解器Matlab安装配置教程
开发语言·其他·matlab
wengqidaifeng6 小时前
python启航:1.基础语法知识
开发语言·python
观北海6 小时前
Windows 平台 Python 极简 ORB-SLAM3 Demo,从零实现实时视觉定位
开发语言·python·动态规划
handler018 小时前
从零实现自动化构建:Linux Makefile 完全指南
linux·c++·笔记·学习·自动化
Ulyanov8 小时前
《PySide6 GUI开发指南:QML核心与实践》 第二篇:QML语法精要——构建声明式UI的基础
java·开发语言·javascript·python·ui·gui·雷达电子对抗系统仿真
码界筑梦坊8 小时前
357-基于Java的大型商场应急预案管理系统
java·开发语言·毕业设计·知识分享
anzhxu8 小时前
Go基础之环境搭建
开发语言·后端·golang
yu85939589 小时前
基于MATLAB的随机振动仿真与分析完整实现
开发语言·matlab