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

相关推荐
10001hours15 分钟前
C语言第12讲
c语言·开发语言
努力的小帅25 分钟前
C++_哈希
开发语言·c++·学习·算法·哈希算法·散列表
知彼解己1 小时前
深入理解 AbstractQueuedSynchronizer (AQS):Java 并发的排队管家
java·开发语言
User_芊芊君子2 小时前
【JavaSE】复习总结
java·开发语言·python
计算机毕业设计木哥2 小时前
计算机毕业设计 基于Python+Django的医疗数据分析系统
开发语言·hadoop·后端·python·spark·django·课程设计
橘颂TA2 小时前
【Qt】项目的创建 and 各个控件的使用
开发语言·qt
我有一颗五叶草2 小时前
线程间通信
java·开发语言
测试界清流2 小时前
postman接口功能测试
开发语言·lua
阿让啊7 小时前
C语言strtol 函数使用方法
c语言·数据结构·c++·单片机·嵌入式硬件
liulilittle7 小时前
OPENPPP2 —— IP标准校验和算法深度剖析:从原理到SSE2优化实现
网络·c++·网络协议·tcp/ip·算法·ip·通信