赋值运算符“=”的重载

对于许多重要的实用类来说,仅有默认的赋值运算符函数是不够的,还需要用户根据实际需要自己对赋值运算符进行重载,已解决遇到的问题。指针悬挂就是这方面的一个典型问题。

1、指针悬挂问题

  在某些特殊情况下,如类中有指针类型时,使用默认的赋值运算符函数会产生错误。例如,

例 1:关于浅层赋值的例子。
#include<iostream>
#include<string.h>
using namespace std;
class STRING{
	private:
		char *ptr;
	public:
		STRING(char *s){  //构造函数 
			cout<<"Constructor called."<<endl;
			ptr=new char[strlen(s)+1];
			strcpy(ptr,s);
		}
		~STRING(){
			cout<<"Destructor called.---"<<ptr<<endl;
			delete ptr;
		}
};
int main(){
	STRING p1("book");
	STRING p2("jeep");
	p2=p1;
	return 0;
}

执行结果:
在这里插入图片描述

(1)程序开始运行,创建对象 p1 和 p2 ,分别调用构造函数,通过运算符 new 分别从内存中动态分配一块空间,字符指针 ptr 指向内存空间,这时两个动态空间中的字符串分别为 “book”和“jeep”。
(2)执行语句“p2=p1;” 时,因为没有用户自定义的赋值运算符函数,于是调用默认的赋值运算符函数,使两个对象 p1 和 p2 的指针 ptr 都指向 new 开辟的同一个空间,这个动态空间中字符串为“book”。
(3)主程序结束,对象逐个撤销。先撤销对象 p2,第 1 次调用析构函数,尽管这时 p1 的指针 ptr 存在,但是其所指向的空间却无法访问了,出现了所谓的 “指针悬挂”,输出出现异常。由于第 2 次执行析构函数中语句“ delete ptr; ”时,企图释放同一空间,从而导致了对同一内存空间的两次释放,这必然引起运行错误。

执行 p2=p1 之前:
在这里插入图片描述
执行 p2=p1 之后:
在这里插入图片描述
撤销对象 p2 后:
在这里插入图片描述

2、用深层复制解决指针悬挂问题

  为了解决浅层复制出现的错误,必须显式地定义一个自己的赋值运算符,使之不但赋值数据成员,而且为对象 p1 和 p2 分配了各自的内存空间,这就是深层复制

  例 2 是在例 1 的基础上,增加了一个自定义的赋值运算符重载函数。

例 2:关于深层复制的例子。
#include<iostream>
#include<string.h>
using namespace std;
class STRING{
	private:
		char *ptr;
	public:
		STRING(char *s){  //构造函数 
			cout<<"Constructor called."<<endl;
			ptr=new char[strlen(s)+1];
			strcpy(ptr,s);
		}
		~STRING(){
			cout<<"Destructor called.---"<<ptr<<endl;
			delete ptr;
		}
		STRING &operator=(const STRING &);  //声明赋值运算符重载函数 属于成员运算符重载函数 
    	//STRING &operator属于使用引用返回函数值,返回函数的值类型为 STRING 
    	//const STRING & 属于使用常引用作为函数参数 学习笔记30 
};
STRING &STRING::operator=(const STRING &s){  //定义赋值运算符重载函数 
	if(this==&s) return *this;  //这里的 &s 表示  s 的地址 
	delete ptr;
	ptr=new char[strlen(s.ptr)+1];
	strcpy(ptr,s.ptr);
	return *this; 
}
int main(){
	STRING p1("book");
	STRING p2("jeep");
	p2=p1;
	return 0;
}

执行结果:
在这里插入图片描述

(1)创建对象 p1 和 p2,分别调用构造函数,通过运算符 new 分别从内存中动态分配一块空间,字符指针 ptr 指向内存空间,这两个动态空间中的字符串分别为“book”和“jeep”。
(2)执行语句“p2=p1”时,调用自定义的赋值运算符重载函数,释放掉了 p2 指针 ptr 所指的旧区域, 又按照新长度分配新的内存空间给 p2,再把对象 p1 的数据成员赋给 p2 的对应的数据成员中。
(3)主程序结束,对象逐个撤销。

执行 p2=p1 之前:

在这里插入图片描述
执行 p2=p1 之后:
在这里插入图片描述
撤销对象 p2 后:
在这里插入图片描述
注意:
类的赋值运算符 “=” 只能重载为成员函数,而不能把它重载为友元函数,因为如果重载为友元函数:

friend STRING &operator=(STRING &p2,STRING &p1); 

表达式 p1=“book” 将被解释为:

operator=(p1,"book");

这没有问题。但是对于表达式 “book”=p1 将被解释为:

operator=("book",p1);

即 C++ 编译器首先将 “book” 转换成一个隐藏的 string 对象,然后使用对象 p2 引用该隐藏对象,编译器并不认为这个表达式是错误的,从而将导致赋值语句上的混乱。因此双目赋值运算符应重载为成员函数的形式,而不能重载为友元函数的形式。

  • 18
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值