剑指offer面试题1——类中的赋值运算符函数

题目:类型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 
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();

}

你可能感兴趣的:(C++,剑指offer笔记)