c++拷贝构造(复制构造函数)详解||浅拷贝和深拷贝||拷贝构造函数的参数能用值传递吗?

目录

 

1.拷贝构造函数

2.浅拷贝和深拷贝

3.拷贝构造函数的参数能用值传递吗?


1.拷贝构造函数

首先,简单介绍一下拷贝构造函数。拷贝构造函数是构造函数的一种,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。

拷贝构造函数将创建好(已初始化)的对象作为参数,返回一个新的对象。

如果我们没有定义拷贝构造函数,系统会自动生成一个默认的拷贝构造函数。

拷贝构造函数的一般形式如下所示:

ClassName(const ClassName& obj)
{}

我们呢来看一个实例:

class  People
{
public:
	//构造函数
	People(int age, string name) :_age(age), _name(name)
	{}
//    拷贝构造函数
	People(const People& obj)
	{
		_age = obj._age;
		_name = obj._name;
		cout << "拷贝构造调用" << endl;
	}
	void Print()
	{
		cout << _name << ":" << _age<< endl;
	}
private:
	int _age;
	string _name;
};

int main()
{
	People xiaoMing(14, "小明");
	People xiaoHong(xiaoMing);
	xiaoMing.Print();
	xiaoHong.Print();
	return 0;
}

打印结果如下:

可以发现小明的属性已经拷贝给了小红,那么如果我们删除掉上述代码中的拷贝构造函数,结果会怎么样?答案是:结果是一样的,这是为什么呢,这是因为系统会生成一个默认的拷贝构造函数,来进行对象初始化对象的操作,但是这种拷贝构造函数只能用于浅拷贝,不能用于深拷贝。接下来我们引出浅拷贝和身拷贝。

2.浅拷贝和深拷贝

假设类中的成员变量有一个指针,我们在类的构造函种为这个指针在堆上申请了内存。如果我们用这个类取初始化其他类会发生什么情况?

我们先来看一个实例:

class  People
{
	public:
	//构造函数
		People(int age, string name, int size = 3) :_age(age), _name(name),_size(size)
	{
			_arr = new int[size];
	}
		~People()
		{
			delete[] _arr;
		}
	void Print()
	{
		cout << _name << ":" << _age<< endl;
	}
private:
	int _age;
	string _name;
	int _size;
	int* _arr;
};

int main()
{
	People xiaoMing(14, "小明");
	People xiaoHong(xiaoMing);	
	return 0;
}

我们在People类中加了两个变量,一个_size,一个int的指针,然后在析构函数种将_arr的内存释放。执行会发现上述代码会报错,这是为什么呢?

如上图,小明首先在堆上有三个字节的大小,通过一个默认的拷贝构造函数(浅拷贝),小红的_arr指针也指向了这块空间,当程序结束的时候,首先调用小明的析构函数释放了这块空间,被释放掉了,小红的析构函数又取释放这块被释放掉的空间,所以程序会报错。

总结一下:

浅拷贝只是复制指向某些对象的指针,并不会对所指内容进行复制。如上:浅拷贝只是把小名的_arr指针指向了小明的_arr指针,并没又进行空间的赋值。当程序结束的时候,不同对象的析构函数会释放同一块内存,报错。

而深拷贝,通过写拷贝构造函数,使堆上的空间也复制一份,当程序结束的时候,不同对象的析构函数会释放的内存虽然内容一样,但是地址不一样,所以不会报错。

在上述的代码种我们增加拷贝构造函数如下之后,程序不会报错。

People(const People& obj)
{
	_age = obj._age;
	_name = obj._name;
	_size = obj._size;
	_arr = new int[_size];
	cout << "拷贝构造调用" << endl;

}

3.拷贝构造函数的参数能用值传递吗?

右函数的传参过程我们可以得知,如果函数的参数不是指针或者引用的时候,我们在传参的时候,会将实参复制给形参。

如果我们将拷贝构造函数的参数去掉引用,那么在调用拷贝构造函数的时候,首先会申请一个新的对象,然后用传入的实参去初始化这个新的对象,这个时候还会调用到我们的拷贝构造函数,如此层层调用,形成无限的递归。

因此,拷贝构造函数的参数必须用引用或者指针。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章