C++面向对象总结(二)拷贝构造和赋值运算符重载

默认的拷贝构造函数:
默认的拷贝构造不是空函数,默认进行浅拷贝,是比较危险的行为;
浅拷贝:只进行变量之间的简单的赋值操作,没有将变量绑定的外部资源进行分配,比如说:一个指针指向一块堆内存,然后该指针将值赋给了另外一个指针;

int *p = new int;
int * q = p;

在这里插入图片描述
如上图。

我们接着上一篇文章来讲:

class CGoods
{
public:
	CGoods(char *const name, int count, float price)
	{
		if (name == NULL)
		{
		_name = new char;
		 *_name = '\0';   //如果是空也给分配一个字节内存,避免操作空指针挂掉
		}
		else
		{
			_name = new char[strlen(name) + 1];
			strcpy(_name, name);
		}
		_count = count;
		_price = price;
	}
	CGoods(CGoods const &src);

	void show();
	void setname(char *name){ strcpy(_name, name); }
	void getname(char *name){ strcpy(name, _name); }
	//char *getname(){ return _name ;}   
	//该函数会将_name的地址返回回去,如果类外拿到地址,可以通过地址解引用来修改内存中的值,不满足面向对象的封装
	float getprice(){  return _price; }
private:
	char *_name;
	int _count;
	float _price;
};
//类外定义,函数名前加上类的作用域,告诉编译器产生的这个函数符号是类的作用域下的
void CGoods::show() 
{ 
	cout << "name: " << _name << "price: " << _price << "count:" << _count << endl; 
}

int main()
{
	CGoods c1("苹果", 10, 8.9);
	CGoods c2("香蕉", 11, 9.8);
	CGoods c3 = c2;
	c1.show();
	c2.show();
	return 0;
}

执行结果:
name: 苹果price: 8.9count:10
name: 香蕉price: 9.8count:11
请按任意键继续. . .

我们将拷贝构造函数单独拿出来说:

//类外实现   拷贝构造函数
//拷贝构造函数,生成新对象,
//该方法属于this和src两个对象共有的,所以可以直接访问对象的成员变量和方法
CGoods :: CGoods(CGoods const &src)//src指向的是右值,this指向的是左值
{
	//开辟一个和src一样大的内存,不能和src指向同一块内存,各自有各自的内存
	_name = new char[strlen(src._name) + 1]; 
	//将this指针的内存中数据初始化为src对象的内存中的数据
	strcpy(_name,src._name);
	_count = src._count;
	_price = src._price;
}

关于拷贝构造函数参数为什么是引用的原因:见上一篇文章

还是上面的程序,我们进行下面的操作:

c1 = c2 ;    //赋值操作

在这里插入图片描述
在这里插入图片描述
从上图我们可以看到:
对象c1和对象c2都有着各自的堆内存,如果将c1 = c2,c1将指向c2的堆内存,那么c1原来的内存该怎么办?是不是就泄露了?嗯是的。

所以,为了解决这个问题,赋值运算符函数 才需要我们重新实现,也就是重载;

默认的赋值运算符重载函数:
只进行简单的赋值,被赋值的对象原来的内存没有释放将被泄露,所以需要我们重载该实现;

赋值运算符函数重载的实现:

//赋值运算符函数参数可以传值吗?const CGoods src
//可以运行  但是给src开辟新的内存,到时候操作的就不是实参的src,而是形参
	void CGoods :: operator=(const CGoods &src)
	{
		//1.防止自赋值,this保存的地址和src引用的对象的地址一样时
		if (this == &src)
			return;
		//2.在接收其他对象的数据之前,先要删掉自己原来已有的外部资源
		delete _name;
		//3.防止浅拷贝,重新申请新的空间,并用src的数据给赋过去
		_name = new char[strlen(src._name) + 1];
		strcpy(_name, src._name);
		_count = src._count;
		_price = src._price;
	}
int main()
{
	CGoods c1("苹果", 10, 8.9);
	CGoods c2("香蕉", 11, 9.8);
	c2 = c1;
	c1.show();
	c2.show();
	return 0;
}

执行结果:
name: 苹果price: 8.9count:10
name: 苹果price: 8.9count:10
请按任意键继续. . .

猜你喜欢

转载自blog.csdn.net/KingOfMyHeart/article/details/89516416