剑指offer总结--面试题1:赋值运算符函数

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

class CMyString
{
public:
    CMyString(char* pData = nullptr);
    CMyString(const CMyString& str);
    ~CMyString(void);

private:
    char* m_pData;
};

 ## 注意点

1.*连续赋值*:函数返回实例自身的引用(*this);

2.*形参为常量引用*:const保证传入的实例不可修改,引用可以节省内存消耗,提高代码效率;

3.*赋值之前释放已有内存*:此为赋值操作,此前被赋值实例中的m_pData已经初始化(即使m_pData指向的是空字符串),为了避免内存泄漏,在分配新内存之前要释放自身已有的空间;

4.*自身不能进行赋值*:结合第3点,在赋值之前释放了已有内存。若自身赋值给自身,则赋值时将找不到相应的内存(被释放了),因此要先进行判断;

 

##知识总结

1.初始化时的赋值调用的是拷贝构造函数;非初始化时的赋值调用的是赋值运算符函数;

如果对象在申明的同时马上进行的初始化操作,则称之为拷贝运算;

如果对象在申明之后,在进行的赋值运算,我们称之为赋值运算

如:

CMyString str2=str1;//调用拷贝构造函数

CMyString str3(str1);//调用拷贝构造函数

CMyString str4;

str4=str1//调用赋值运算符函数

 

2.深拷贝与浅拷贝

- 浅拷贝:简单的地址赋值,在进行delete释放内存时可能会发生同一块内存的重复释放;

- 深拷贝:先new出新的内存,在新的内存地址进行内容赋值;

默认的拷贝构造函数和赋值运算符函数是以浅拷贝的方式进行的。

 

3.赋值运算符函数(返回左值的引用)

格式:

A A::operator=(A &a)

{    //……    

return *this;

}

问题:返回自身就可实现连续赋值,为何要返回自身的引用?

-赋值返回引用

x = y = z  先执行y = z,返回y的引用,执行x = y

-赋值不返回引用

x = y = z  先执行y = z,返回用y初始化的临时对象(注意临时对象都是常对象),再执行x = y的临时对象(要求operator=(const X&) ),返回用x初始化的临时对象(此处要求拷贝构造函数必须为X(const X&)  )。

即每返回一次临时对象时需要调用一次拷贝构造函数和一次析构函数。

*所以也并非必须返回引用,返回引用的好处既可以于赋值的原始语义已知,又可避免拷贝构造函数和析构函数的调用。*

 

4.使用strlen()是返回的长度是不包含'\0'的,如果要使用strcpy(str1,str2)进行复制时,

str1的长度应该要为strlen(str2)+1,即预留一个空字符位。

 

 

源代码:https://github.com/zhedahht/CodingInterviewChinese2/tree/master

#include<cstring>
#include<cstdio>

class CMyString
{
public:
    CMyString(char* pData = nullptr);
    CMyString(const CMyString& str);
    ~CMyString(void);

    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)
{
    if(this == &str)
        return *this;

    delete []m_pData;
    m_pData = nullptr;

    m_pData = new char[strlen(str.m_pData) + 1];
    strcpy(m_pData, str.m_pData);

    return *this;
}

// ====================测试代码====================
void CMyString::Print()
{
    printf("%s", m_pData);
}

void Test1()
{
    printf("Test1 begins:\n");

    char* text = "Hello world";

    CMyString str1(text);
    CMyString str2;
    str2 = str1;

    printf("The expected result is: %s.\n", text);

    printf("The actual result is: ");
    str2.Print();
    printf(".\n");
}

// 赋值给自己
void Test2()
{
    printf("Test2 begins:\n");

    char* text = "Hello world";

    CMyString str1(text);
    str1 = str1;

    printf("The expected result is: %s.\n", text);

    printf("The actual result is: ");
    str1.Print();
    printf(".\n");
}

// 连续赋值
void Test3()
{
    printf("Test3 begins:\n");

    char* text = "Hello world";

    CMyString str1(text);
    CMyString str2, str3;
    str3 = str2 = str1;

    printf("The expected result is: %s.\n", text);

    printf("The actual result is: ");
    str2.Print();
    printf(".\n");

    printf("The expected result is: %s.\n", text);

    printf("The actual result is: ");
    str3.Print();
    printf(".\n");
}

int main(int argc, char* argv[])
{
    Test1();
    Test2();
    Test3();

    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值