浅复制构造函数和深复制构造函数

1、浅复制构造函数

      编译器提供了默认构造函数、析构函数,同时也提供了赋值构造函数。编译器默认提供的复制构造函数只是把传递进来的对象的每个成员变量复制到新的成员变量中去。然后两个对象中的变量均指向存放类成员变量的那块内存区域。假设该变量不是指针变量一般不会立即出错。假设该变量是指针变量,如图:

 

       现在对象a有一指针变量x,它指向堆中存放6的那块内存区域。我们将对象a复制到对象b,如:

A b = a ;

       由于要复制对象,因此自动调用默认构造函数。调用过程为:

       首先,将对象a作为参数传递到默认复制构造函数,然后将对象a的指针成员变量x复制对象b中,这样现在两个对象的指针成员变量x都指向同一内存区域。这样当这两个对象中的任何一个超出作用域时,都会产生致命的错误。比如说我们将对象a删除,那么析构函数将自动释放堆中存放6的那块内存空间。而对象b的指针成员变量x任然指向该空间,由于该空间已经不存在了,那么对象b的指针成员变量x成了一个迷途指针。该程序面临崩溃的边缘。

       我们可以用一个程序来说明这个问题:

#include <iostream>
using namespace std;

class A
{
public:
	A(){x = new int ;*x = 5 ;}
	~A() {delete x ; x = NULL ;}
	A(const A& a)
	{
		cout << "复制构造函数执行!\n" << endl ;
		x = a.x ;
	}
	void print() const{cout << *x << endl;}
	void set(int i){*x = i ;}
private:
	int *x ;
};

int main()
{
	A *a = new A() ;
	cout << "a: " ;
	a->print() ;
	cout << endl ;

	A b = (*a); //两个对象的指针成员变量指向同一个内存空间
	cout << "b: " ;
	b.print() ;
	cout << endl ;

	a->set(32) ;
	cout << "b: " ;
	b.print() ;//可以看到b输出的值是32。说明两个对象的指针成员变量是指向同一个内存空间
	cout << endl ;
	return 0 ;
}

程序运行的结果:

       程序运行的结果表示两个对象的指针成员变量x是指向同一个内存空间。当我们在程序将要结束的时候删除对象a的指针成员变量指向的内存空间时,程序运行后崩溃了。

#include <iostream>
using namespace std;

class A
{
public:
	A(){x = new int ;*x = 5 ;}
	~A() {delete x ; x = NULL ;}
	A(const A& a)
	{
		cout << "复制构造函数执行!\n" << endl ;
		x = a.x ;
	}
	void print() const{cout << *x << endl;}
	void set(int i){*x = i ;}
private:
	int *x ;
};

int main()
{
	A *a = new A() ;
	cout << "a: " ;
	a->print() ;
	cout << endl ;

	A b = (*a); //两个对象的指针成员变量指向同一个内存空间
	cout << "b: " ;
	b.print() ;
	cout << endl ;

	a->set(32) ;
	cout << "b: " ;
	b.print() ;//可以看到b输出的值是32。说明两个对象的指针成员变量是指向同一个内存空间
	cout << endl ;
	delete a ;  //删除对象a的指针成员变量x指向的内存空间
	return 0 ;
}

程序崩溃了。

2、深复制构造函数

       为了解决浅层复制导致的迷途指针问题,我们必须创建自己的复制构造函数,并且在函数里为我们的成员分配内存,这样,在分配完内存后,旧对象的成员变量就可以复制到新的内存区域中,两个对象的成员变量都各自拥有自己的内存区域,一个对象在析构后不会再影响到另一个,我们把这种复制方式叫做深层拷贝。请看下面的程序:

#include <iostream>
using namespace std;

class A
{
public:
	A(){x = new int ;*x = 5 ;}
	~A() {delete x ; x = NULL ;}//删除指针x指向的内存空间
	A(const A& a)
	{
		cout << "复制构造函数执行!\n" << endl ;
		//在堆中开辟一块新空间存放对象a的内容
		x = new int ; //这样两个对象的指针成员变量x都指向不同的内存空间
		*x = *(a.x) ; //进行深复制
	}
	void print() const{cout << *x << endl;}
	void set(int i){*x = i ;}
private:
	int *x ;
};

int main()
{
	A *a = new A() ;
	cout << "a: " ;
	a->print() ;
	cout << endl ;

	A b = (*a); //两个对象的指针成员变量指向不同的内存空间
	cout << "b: " ;
	b.print() ;
	cout << endl ;

	a->set(32) ;
	cout << "b: " ;
	b.print() ;//可以看到b输出的值仍是5。说明两个对象的指针成员变量是指向不同的内存空间
	cout << endl ;
	delete a ;  //删除对象a的指针成员变量x指向的内存空间,这里会自动调用析构函数,而不会影响对象b
	return 0 ;
}

程序运行的结果如下:

程序没有崩溃,正常运行。深层拷贝的示意图:

 


          我们可以看到对象a的指针成员变量x指向堆中的内存空间和对象b的指针成员变量x指向堆中的内存空间不是同一个内存空间。


 



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值