拷贝构造函数 浅拷贝与深拷贝

2023-07-30 09:46:40 浏览数 (2)

拷贝构造函数

上一期中我们讲述了构造函数的相关内容,谈到构造函数在形式上有几种分类,即带参数的、不带参数的以及参数列表初始化的,还有一种传引用的构造函数,称为拷贝构造函数,顾名思义,就是起到拷贝的功能,通过一个已经存在的类对象的相关数据初始化一个新的类对象。

我们还是用Point这个类作为例子进行讲解,拷贝构造函数就是参数类型为引用类型的构造函数。

代码语言:javascript复制
class Point
{
	double x,y;
	public:
		Point(Point & point);
};

浅拷贝

所有的类都有自己的拷贝构造函数,如果程序员自己没有写拷贝构造函数,那么系统会默认生成一个缺省的拷贝构造函数,它采取逐位复制的方法进行对象拷贝,又称为浅拷贝。

我们自己写一个Point类的浅拷贝的拷贝构造函数作为例子:

代码语言:javascript复制
Point::Point(Point & point)
{
	x=point.x;
	y=point.y;
}

这就是浅拷贝,即逐位复制。看样子没什么毛病,为什么说它浅呢?

实际上,如果数据成员都是基本数据类型,浅拷贝是没有什么问题的。

但是,当一个类的数据成员中含有指针的时候,浅拷贝就会出事。

我们把Point类修改一下,增加一个指针指向Point类,为了安全,我们把这个指针初始化为NULL:

代码语言:javascript复制
class Point
{
	double x,y;
    Point * p=NULL;
	public:
		Point(Point & point);
};

然后我们用浅拷贝:

代码语言:javascript复制
Point::Point(Point & point)
{
	x=point.x;
	y=point.y;
    p=point.p;
}

首先x和y是没有问题的,指针p的值虽然是相同了,但是我们的目的是想让指针的值相同吗,显然不是,是想让它们指向的内存单元具有相同的值,如果采用这样的浅拷贝,那么这两个指针指向的是同一块内存,有同学可能会说,这好像没有问题啊,这不也成功复制了吗?问题在于一旦我们修改其中一个类对象的p指向的内容,那么另一个类对象的数据也会改变,因为它们指向的是同一块内存。因此,我们在这种情况下需要用深拷贝。

深拷贝

通过上面的分析,我们知道浅拷贝的问题在于,这两个指针指向了同一块内存,所以只要给生成的类对象一块新内存空间就可以解决问题了:

代码语言:javascript复制
Point::Point(Point & point)
{
	x=point.x;
	y=point.y;
    if(point.p)
    {
		p=new Point;
		p->x=point.p->x;
		p->y=point.p->y;
	}
}

在这里你可以看到,我们是首先判断p是不是空指针,不是空指针我们再复制,这里非常重要,如果没有这个判断,一旦p是空指针,而我们还是继续操作,引发系统不可预知的错误。

0 人点赞