《剑指Offer》思考总结——第一题:赋值运算符函数

       自我总结一下《剑指Offer》中的题目,也欢迎有兴趣的朋友提出意见或对错误进行指正。

第一题 赋值运算符函数

所需知识基础:拷贝构造,构造析构,重载操作符

题目:

 这道题是面试时经常让手写的代码之一。主要考察的知识点正如书中所说:

1.是否把返回值类型声明为该类型的引用,并在函数结束前返回实例自身的引用(*this)。只有返回一个引用,才可以允许连续赋值。否则如果函数的返回值是void,则应用该赋值运算符将不能进行连续赋值。假设有3个CMyString的对象:str1、str2、str3,在程序中语句str1=str2=str3将不能通过编译。

2.是否把传入的参数的类型声明为常量引用。如果传入的参数不是引用而是实例,那么从形参到实参会调用一次拷贝构造函数。把参数声明为引用可以避免这样的无谓消耗,能提高代码的效率。同时,我们在赋值运算符函数内不会改变传入的实例状态,因此应该为传入的引用参数加上const关键字。

3.是否释放实例自身已有的内存。如果我们忘记在分配新内存之前释放已有的空间,则程序将出现内存泄漏。

4.判断传入的参数和当前的实例(*this)是不是同一个实例。如果是同一个,则不进行赋值操作,直接返回。如果事先不判断就进行赋值,那么在释放实例自身内存的时候就会导致严重的问题:当*this和传入的参数是同一个实例时,一旦释放了自身内存,传入的参数的内存也同时被释放了,因此再也找不到需要赋值的内容了。

关于上述需要第2点的解释:

如果允许拷贝构造函数传值,就会在拷贝构造函数内调用拷贝构造函数,会形成永无休止都得调用递归而栈溢出。例子如下:

class CBase
{
public:
	int a;
	//CBase(CBase base)              //错  相当于CBase(CBase base = base)
	//{                              //相当于给形参又初始化,无限循环下去
	//	cout<<"CBase::CBase"<<endl;
	//}
	CBase(const CBase &base)         //对   拷贝构造的形参应该是一个引用
	{
		cout<<"CBase::CBase"<<endl;
	}
};

如果注意到上述几点,就可以写出本题代码:

CMyString &operator = (const CMyString &str)
{
	//判断是否是同一个对象,是同一个就跳出函数
	//怎么判断是不是同一个对象?
	//对象是一个变量,变量是内存的别名,地址相同,对象就是一个
	if(this == &str) return *this;  /*返回一个对象*/
	//回收之前的空间
	delete []m_pData;    /*构造函数中类成员是字符串数组,则应释放一个数组*/
	m_pData = 0;
	//申请新空间
	m_pData = new char[strlen(str.m_pData)+1];  /*注意“\0”*/
	//将内容拷贝过来
	strcpy_s(m_pData,strlen(str.m_pData)+1,str.m_pData);
	//返回一个对象
	return *this;
}

另外,本题可以扩展为模仿写出String类的原理。还应涉及到字符串的拼接等功能。由于功能过多,我只写了一部分,供大家参考:

#include <iostream>
using namespace std;
 
class CMyString
{
private:
	char *m_pStr;
public:
	CMyString()
	{
		m_pStr = new char[2];
		m_pStr[0] = 0;
		m_pStr[1] = 0;
	}
	CMyString(const char* pStr)
	{
		if (!pStr)
		{
			m_pStr = new char[2];
			m_pStr[0] = 0;
			m_pStr[1] = 0;
			return;
		}
 
		m_pStr = new char[strlen(pStr)+1];
		strcpy_s(m_pStr,strlen(pStr)+1,pStr);
	}
	CMyString(const char Str)
	{
		m_pStr = new char[2];
		m_pStr[0] = Str;
		m_pStr[1] = 0;
	}
	CMyString(CMyString &Str)
	{
		m_pStr = new char[strlen(Str.m_pStr)+1];
		strcpy_s(m_pStr,strlen(Str.m_pStr)+1,Str.m_pStr);
	}
	~CMyString()
	{
		if (m_pStr)
		{
			delete []m_pStr;
			m_pStr = 0;
		}
	}
	CMyString& operator=(const CMyString &Str)
	{
		if (this == &Str) return *this;
 
		delete []m_pStr;
		m_pStr = 0;
 
		m_pStr = new char[strlen(Str.m_pStr)+1];
		strcpy_s(m_pStr,strlen(Str.m_pStr)+1,Str.m_pStr);
 
		return *this;
	}
	CMyString& operator=(const char *pStr)
	{
		if (!pStr)
		{
			m_pStr = new char[2];
			m_pStr[0] = 0;
			m_pStr[1] = 0;
			return;
		}
 
		delete []m_pStr;
		m_pStr = 0;
 
		m_pStr = new char[strlen(pStr)+1];
		strcpy_s(m_pStr,strlen(pStr)+1,pStr);
 
		return *this;
	}
	CMyString& operator=(const char str)
	{
		delete []m_pStr;
		m_pStr = 0;
 
		m_pStr = new char[2];
		m_pStr[0] = str;
		m_pStr[1] = 0;
 
		return *this;
	}
	char* operator+(const CMyString & Str)
	{
		char *pTmp = 0 ;
 
		pTmp = new char[strlen(this->m_pStr) + strlen(Str.m_pStr)+1];
		strcpy_s(pTmp,strlen(this->m_pStr) + strlen(Str.m_pStr)+1 ,  this->m_pStr );
		strcat_s(pTmp,strlen(this->m_pStr) + strlen(Str.m_pStr)+1 , Str.m_pStr );
		return pTmp;
	}
	CMyString& operator+=(const CMyString &Str)
	{
		char *pTmp = 0;
 
		pTmp = new char[strlen(this->m_pStr)+strlen(Str.m_pStr)+1];
		strcpy_s(pTmp,strlen(this->m_pStr)+strlen(Str.m_pStr)+1,this->m_pStr);
		strcat_s(pTmp,strlen(this->m_pStr)+strlen(Str.m_pStr)+1,Str.m_pStr);
 
		delete []m_pStr;
		m_pStr = 0;
 
		m_pStr = new char[strlen(pTmp)+1];
		strcpy_s(m_pStr,strlen(pTmp)+1,pTmp);
 
		delete []pTmp;
		pTmp = 0;
 
		return *this;
	}
	CMyString &operator+=(const char *pStr)
	{
		if (!pStr)
		{
			return *this;
		}
		char *pTmp = 0;
 
		pTmp = new char[strlen(this->m_pStr)+strlen(pStr)+1];
		strcpy_s(pTmp,strlen(this->m_pStr)+strlen(pStr)+1,this->m_pStr);
		strcat_s(pTmp,strlen(this->m_pStr)+strlen(pStr)+1,pStr);
 
		delete []m_pStr;
		m_pStr = 0;
 
		m_pStr = new char[strlen(pTmp)+1];
		strcpy_s(m_pStr,strlen(pTmp)+1,pTmp);
 
		return *this;
	}
	CMyString & operator+=(char str)
	{
		char cTmp[2];
		cTmp[0] = str;
		cTmp[1] = 0;
		(*this) += cTmp;
		return *this;
	}
	friend ostream &operator<<(ostream& out,CMyString &Str);
	friend istream &operator>>(istream& in,CMyString &Str);
};
 
ostream &operator<<(ostream& out,CMyString &Str)
{
	out<<"CMyString: "<<Str.m_pStr;
	return out;
}
 
istream &operator>>(istream& in,CMyString &Str)
{
	in>>Str.m_pStr;
	return in;
}
 
int main()
{
	CMyString Str("123");
	CMyString Str1("789");
	Str = "12345";
	Str += Str1;
	cout <<  Str+ Str1<< endl;
 
	cout << Str <<endl;
 
 
	system("pause");
	return 0;
}

可以看出,各函数都具有相同的思想。

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值