题目:类型CMyString的类声明中,为该类型添加赋值运算符函数。
解题思路:
1.赋值运算符函数:是一种重载运算符。本质上也是一种函数。因此,有函数对应的特性:返回值、函数名、形参列表。
class CMyString
{
public:
CMyString(char* pData=nullptr);
CMyString(const CMyString& str);
~CMyString();
CMyString& operator=(const CMyString& str);
void Print();
private:
char* m_pData; //指针指向字符数组的首地址
};
- ①赋值运算符重载的函数名:operator=
- ②返回值类型通常使用该类型的引用 CMyString&:目的是为了能够连续赋值,如定义3个对象,str3=str2=str1
- ③形参const CMyString& str 为常量引用。若不使用引用而是用实例,则从形参到实参会再调用一次拷贝构造函数,是一种无谓的消耗;此外,由于传入的实例一般不会改变,因此使用常量。
- ④赋值之前,首先要判断当前实例和传入的参数是否为同一个实例。如果是,则不需要赋值。
- ⑤赋值的时候,要释放掉当前实例的内存空间,然后分配新的内存。
- ⑥在⑤的基础上,考虑异常安全性问题,旨在避免内存溢出,可以有两种解决思路: 第一种,先new分配内容,然后再释放已有的内容;第二种,构建一个中间变量保存当前实例。
实验代码如下:
/************************************************************************/
/* 剑指offer1:赋值运算符函数operator= */
/************************************************************************/
#include <string.h>
class CMyString
{
public:
CMyString(char* pData=nullptr);
CMyString(const CMyString& str);
~CMyString();
CMyString& operator=(const CMyString& str); //返回类型用类的引用(目的:多次进行赋值);形参列表用常量引用(引用:避免了从形参到实参还要调用一次拷贝构造函数;常量是因为传入示例不会改变
void Print();
private:
char* m_pData; //指针指向字符数组的首地址
};
/************************************************************************/
/* 实现构造函数 */
/************************************************************************/
CMyString::CMyString(char* pData)
{
if (pData==nullptr)
{
m_pData=new char[1];
m_pData[0]='\0';
}
else
{
int length = strlen(pData);
m_pData =new char[length+1];
strcpy(m_pData,pData);
}
}
/************************************************************************/
/* 实现拷贝构造函数 */
/************************************************************************/
CMyString::CMyString(const CMyString& str)
{
int length=strlen(str.m_pData);
m_pData=new char[length+1];
strcpy(m_pData,str.m_pData);
}
/************************************************************************/
/* 析构函数 */
/************************************************************************/
CMyString::~CMyString()
{
delete[] m_pData;
}
/************************************************************************/
/* 类的操作符重载 */
/************************************************************************/
CMyString& CMyString::operator=(const CMyString& str)
{
//①首先判断两个示例是否相等,返回*this(实例自身的引用)
if (this==&str)
{
return *this;
}
//②释放被赋值的实例已有内存,this指针隐含地指向数据delete this->m_pData;
delete []m_pData; //注意:释放后指针为空指针
m_pData=nullptr;
//③申请新的空间并赋值
m_pData=new char(sizeof(strlen(str.m_pData)+1));
strcpy(this->m_pData,str.m_pData);
return *this;
}
void CMyString::Print()
{
printf("%s\n",m_pData);
}
void test1()
{
printf("给另一个量赋值:\n");
char *text ="hello world";
CMyString str1(text);
CMyString str2;
str2=str1;
printf("期望的结果为:%s\n",text);
printf("实际操作结果为:");
str2.Print();
printf("\n");
}
void test2()
{
printf("\n\n给自己赋值\n");
char *text="hello world";
CMyString str1(text);
str1=str1;
printf("期望的结果为:%s\n",text);
printf("实际操作结果为:");
str1.Print();
printf("\n");
}
void test3()
{
printf("\n\n连续赋值:\n");
char *text="hello world";
CMyString str1(text);
CMyString str2,str3;
str3=str2=str1;
printf("期望的结果为:%s\n",text);
printf("实际操作结果为:");
str2.Print();
printf("\n");
str3.Print();
printf("\n");
}
int main()
{
test1();
test2();
test3();
}