C++基础之赋值运算符函数(七)

在C++类中编译器会自动创建一个构造函数,析构函数,拷贝构造函数,赋值运算符函数,赋值运算符函数顾名思义是在进行赋值运算时自动调用,其基本的形式如下

返回类型 类名::&operator=(参数列表)

{

//

}

class Computer
{
public:
	Computer(const char * name,int price)
		:_name(new char[strlen(name)+1]())
	{

		_price = price;
		cout << "Computer构造函数" << endl;
		strcpy(_name, name);
	}

	Computer(const Computer& rhs)
		:_name(new char[strlen(rhs._name) + 1]())
	{
		_price = rhs._price;
		cout << "Computer拷贝构造函数" << endl;
		strcpy(_name, rhs._name);
	}
	void set_Price(int price)
	{
		_price = price;
	}

	void set_Brand(const char* name) 
	{
		strcpy(_name, name);
	}


	void print()
	{
		cout << "name" << _name << endl;
		cout << "price" << _price << endl;
	}
	~Computer()
	{
		cout << "析构函数" << endl;
		if(_name != nullptr)
		{ 
			delete[] _name;
			_name = nullptr;
		}
	}
private:
	int _price;
	char* _name;
};

int main()
{
   	Computer com1("Lenovo", 1500);
	Computer com2("Thinkipad",2000);
    com1=com2;
    com1.operator(com2);
}

当我们通过Computer类来创建两个对象com1和com2时当执行赋值时,将对象com2赋给com1时会自动调用赋值运算符函数,也可写成com1.operator(com2);这要与Computer com1=com2;区分因为com1=com2是存在的两个对象,所以不存在构造,而第二个是创建com1然后在将com2拷贝给com1。满足拷贝构造函数的调用时机。

在编写赋值运算符函数时需要注意的几个问题:

	//赋值运算函数
	Computer& operator=(const Computer& com)
	{ 
		
        _name=com._name;
        _price=com._price;
		return *this;
		//this表示对象的指针用于区分不同对象,通过解引用运算符指向对象
	}

当我们这么编写赋值运算符函数时会出现什么问题呢?

首先在Computer类中_name我们申请了堆空间,如果直接_name=com._name;那么之前_name指向的那块内存区域就没有人可以指向它了并且他还没有被释放,这就会导致一个内存泄漏的问题。

其次_name=com._name;这时com1._name和com2._name指向了同一块内存空间,当com1调用析构函数时就已经将那块堆空间销毁了,而com2调用析构函数时会继续释放那块堆空间,这就会导致一个双重释放(double free)的问题。

因此根据上两个问题我们把代码修改成

Computer &operator=(const Computer &com)
{
//解决问题一内存泄漏
    delete[] _name;
    _name=nullptr;
    //解决问题二改用深拷贝
    _name=new char[strlen(com._name)+1]();
    strcpy(_name,com._name);
    _price=com._price;
    return *this;
}

以上代码我们就可以解决com1=com2的问题,那么如果com1=com1会怎么样?

那么在  delete[] _name;时会把com1的_name指向的堆空间释放,直接导致赋值出错程序崩溃。因此我们需要在考虑到自复制的情况。

Computer &operator=(const Computer &com)
{
    //解决问题三自复制的情况,确保两个对象的地址不同
    if(this != &com)
    {
        //解决问题一内存泄漏
        delete[] _name;
        _name=nullptr;
        //解决问题二改用深拷贝
        _name=new char[strlen(com._name)+1]();
        strcpy(_name,com._name);
        _price=com._price;
    }
    return *this;
}

关于赋值运算符函数的几个问题:

1.为什么形参是Computer的引用,因为如果不加引用时const Computer com=com1;这样的话满足拷贝构造函数的调用时机,会多调用一次拷贝构造函数。

2.为什么要加const,因为不加const时变成 Computer& com=com1;那么传递的实参是右值的话就会报错,只有const的左值才能绑定右值。其中左值是可以取地址的,右值是不能取地址的其中包括临时变量,临时对象,匿名对象,匿名变量。

3.为什么返回值要是Computer的引用,因为如果不加引用还是会满足拷贝构造函数的调用时机,导致多调用一次拷贝构造函数。

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值