C++赋值运算符函数

题目:给出如下类型为CMyString的声明,请为该类型添加赋值运算符函数。

class CMyString
{
    
    
public:
	CMyString(char* pData = NULL);
	CMyString(const CMyString& str);
	~CMyString(void);
private:
	char* m_pData;
};

面试官关注点:

1.是否把返回值的类型声明为该类型的引用,并在函数结束前返回实例自身的引用(*this)。只有返回一个引用,才可以进行连续赋值。否则,如果函数返回值是void,运用该赋值函数将不能做连续赋值。例如:有三个对象:str1、str2、str3,str1=str2=str3这样的赋值语句将会出错。
2.是否把传入的参数的类型声明为常量引用。形参到实参会调用拷贝构造函数,而把参数声明为引用可以避免内存消耗,提高代码执行效率。 同时,在赋值运算符中不会改变传入实例的属性,所以应在传参前加上(const)关键字。
3.是否是否实例自身内存。程序结束后如果没有释放实例所在的内存,会造成内存泄漏。
4.是否判断传入的参数和当前的实例(*this)是否是同一个。如果是同一个,不用赋值,直接返回。当(*this)与传入的的参数是同一个实例时,一旦自身内存释放,传入参数的内存也会被释放,就无法找到需要赋值的内容。

基于以上要求可以写成如下代码:

CMyString& CMyString::operator=(const CMyString& str)
{
    
    
	//检查自赋值
	if(this == &str)
	{
    
    	
		return *this;
	}
	//释放原资源
	delete [] m_pData;
	//分配新内存
	m_pData = new char(strlen(str.m_pData) + 1);
	strcpy_s(m_pData, strlen(str.m_pData) + 1, str.m_pData);
	//返回引用
	return *this;
}

可以看出,在分配内存前用delete释放了pData的内存。如果此时内存不足导致new char抛出异常,
pData将是一个空指针,这样容易导致程序崩溃 。

所以就有了如下改进:

CMyString& CMyString::operator=(const CMyString& str)
{
    
    
	if (this != &str)		//检查自赋值
	{
    
    
		CMyString tmp(str);	//拷贝构造临时变量
		char* p = tmp.m_pData;//交换对象与临时对象的数据
		tmp.m_pData = this->m_pData;
		this->m_pData = p;
	}
	return *this;
}

在这个函数中,我们先创建一个临时实例tmp,接着把
tmp.m_pData和实例自身的m_pData做交换。由于tmp是局部变量,但程序运行到if的外面时就出了该变量的作用域,就会自动调用
tmp的析构函数,把 tmp.m_pData所指向的内存释放掉。由于
tmp.m_pData指向的内存就是实例之前mpData的内存,这就相当于自动调用析构函数释放实例的内存

测试:
在类中加入Show函数,显示当前各对象的值

void Show()	//测试
	{
    
    
		if (m_pData == nullptr)	cout << "NULL" <<endl;
		else
			cout << this->m_pData << endl;
	}

main函数:

int main()
{
    
    
	char str[] = "Hello C++";

	//实例化三个对象
	CMyString str1;
	CMyString str2;
	CMyString str3;

	str1 = str;	//赋值
	cout << "str1是: " ;
	str1.Show();

	str1 = str1;//自赋值
	cout << "str1是: ";
	str1.Show();

	str3 = str2 = str1;//连续赋值
	cout << "str2是: ";
	str2.Show();
	cout << "str3是: ";
	str3.Show();

	return 0;
}

运行结果:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Gunanhuai/article/details/103050369
今日推荐