C++拷贝构造与赋值重载问题

拷贝构造函数

何时调用拷贝构造函数

① 对象作为函数的参数,以值传递的方式传给函数。 
② 对象作为函数的返回值,以值的方式从函数返回
③ 使用一个对象给另一个对象初始化

拷贝构造函数:
         用一个已经存在的对象来生成一个相同类型的新对象。(浅拷贝)
默认的拷贝构造函数:
         如果自定义了拷贝构造函数,编译器就不在生成默认的拷贝构造函数。 
         如果没有自定义拷贝构造函数,但在代码中用到了拷贝构造函数,编译器会生成默认的拷贝构造函数。
深拷贝&浅拷贝:
         系统默认的拷贝构造函数是浅拷贝,类中含有指针类型的变量,须自定义拷贝构造函数用深拷贝来实现。
         浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,所指向的空间内容并没有复制,而是由两个对象共用。深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。

#include<iostream>
 
class CGoods
{
public:
	CGoods(const char* name, double price, int amount)
	{
		std::cout << this << " :CGoods::CGoods(char*,float,int)" << std::endl;
		mname = new char[strlen(name) + 1]();
		strcpy(mname, name);
		mprice = price;
		mamount = amount;
	}
 
	CGoods()
	{
		std::cout << this << " :CGoods::CGoods()" << std::endl;
		mname = new char[1]();
	}
 
         ~CGoods()
	{
		std::cout << this << " :CGoods::~CGoods()" << std::endl;
		delete[] mname;
	}
 
private:
	char*  mname;
	double mprice;
	int mamount;
};
 
int main()
{
	CGoods good1("car1", 10.1, 10);
	CGoods good2 = good1;
	return 0;
}

调用两次析构一次构造会产生什么后果

对象1浅拷贝一个对象2使得对象1与对象2指向同一块外部资源,当析构时,先析构对象2,同时释放对象2指向的外部资源,然后析构对象1,这样会产生不可预料的结果。

解决浅拷贝构造函数有哪些方法

  1. 将拷贝构造函数声明为私有的,外部不能够进行调用(在编译时期不能 编译过)
  2. 重新自定义拷贝构造函数

自定义拷贝构造函数

CGoods(const CGoods &rhs)
{
	std::cout << this << " :CGoods::CGoods(const CGoods &rhs)" << std::endl;
	mname = new char[strlen(rhs.mname) + 1]();
	strcpy(mname, rhs.mname);
	mprice = rhs.mprice;
	mamount = rhs.mamount;
}

 注意:拷贝构造函数传参必须传引用。若正常传,则会不断地递归去生成新形参对象,最后导致栈溢出。也不能用*,若写成 CGoods(const CGoods* rhs),就会变成一个构造函数,CGoods*传的是已存在对象的地址。

赋值运算符重载

赋值运算符的重载函数:
        用一个已存在的对象赋值给相同类型的已存在对象。(浅拷贝)
默认赋值运算符的重载函数:
        赋值运算符重载函数用于类对象的赋值操作,当我们未实现该函数时,编译器会自动为我们实现该函数。同拷贝构造函数一样,系统默认的赋值运算符重载函数是浅拷贝,类中含有指针类型的变量,须自定义赋值运算符重载函数用深拷贝来实现。


CGoods& operator=(const CGoods& rhs)
{
	std::cout << this << " CGoods::operator=(const CGoods&)" << std::endl;
	if (this != &rhs)//判断是否给自己赋值
	{
		delete[] mname;//防止内存泄漏
		mname = new char[strlen(rhs.mname) + 1]();
 
		strcpy(mname, rhs.mname);
		mprice = rhs.mprice;
		mamount = rhs.mamount;
	}
	return *this;
}
 
int main()
{
	CGoods good1("car1", 10.1, 10);
	CGoods good2;
	good2 = good1;
	return 0;
}


为什么要避免自赋值呢?
1)自己给自己赋值完全是毫无意义,为了效率。

2)如果类的数据成员中含有指针,自赋值有时会导致灾难性的后果。对于指针间的赋值,先要将p所指向的空间delete掉,然后再为p重新分配空间,将被拷贝指针所指的内容拷贝到p所指的空间。如果是自赋值,那么p和被拷贝指针是同一指针,在赋值操作前对p的delete操作,将导致p所指的数据同时被销毁
 

猜你喜欢

转载自blog.csdn.net/zhangfei5354/article/details/89176163
今日推荐