赋值运算符重载函数 返回引用和返回对象的区别

先上代码

#include "stdafx.h"
#include <string>

using namespace std;

class CStudent
{
public:
    CStudent(char *pName) :m_pName(NULL)
    {
        if (NULL == pName)
        {
            return;
        }
        m_pName = new char[strlen(pName) + 1];
        strcpy(m_pName, pName);
        printf("CStudent: address:0x%08x name:%s\n", this, m_pName);
    }
    ~CStudent()
    {
        printf("~CStudent: address:0x%08x name:%s\n", this, m_pName);
        delete m_pName;
    }
    //拷贝构造函数
    CStudent(const CStudent &a) :m_pName(NULL)
    {
        if (NULL == a.m_pName)
        {
            return;
        }
        int len = strlen(a.m_pName);
        this->m_pName = new char[len + 20];
        memset(m_pName, 0, len + 20);
        strcpy(m_pName, a.m_pName);
        strcat(m_pName, "_copy_construct"); // 为了测试
        printf("copy construct: address:0x%08x name:%s\n", this, this->m_pName);
    }
public:
#if 01
    //重载赋值函数 返回对象
    CStudent   operator=(const CStudent &b)
    { 
        if (&b == this)
        {
            return *this;
        }
        if (NULL == b.m_pName)
        {
            delete m_pName;
            m_pName = NULL;
            return *this;
        }
        delete m_pName;
        int len=strlen(b.m_pName);
        m_pName=new char[len+1];
        memset(m_pName, 0, len+1);
        strcpy(m_pName,b.m_pName);
        return *this;
    }
#else
    //重载赋值函数 返回引用
    CStudent& operator=(const CStudent &b)
    {
        if (&b == this)
        {
            return *this;
        }
        if (NULL == b.m_pName)
        {
            delete m_pName;
            m_pName = NULL;
            return *this;
        }
        delete m_pName;
        int len = strlen(b.m_pName);
        m_pName = new char[len + 1];
        memset(m_pName, 0, len+1);
        strcpy(m_pName, b.m_pName);
        return *this;
    }
#endif
    //或者 我们也可以这样重载赋值运算符 即不返回任何值。如果这样的话,他将不支持客户代买中的链式赋值
    //例如a=b=c will be prohibited!
    //void operator=(const CStudent &a);

private:
    char *m_pName;
};



int main()
{
    {
        CStudent  liubei("liubei");
        CStudent  guanyu("guanyu");
        CStudent  zhangfei("zhangfei");
        //CStudent dd(NULL);
        //CStudent ff(dd);
        liubei = guanyu = zhangfei;
    } 
    system("pause"); 
    return 0;
}

一、如果赋值运算符返回的是返回对象本身
执行结果如下图所示
赋值运算符重载函数 返回引用和返回对象的区别_第1张图片
1 释放对象原来的堆资源
2 重新申请堆空间
3 拷贝源的值到对象的堆空间的值
4 创建临时对象(调用临时对象拷贝构造函数),将临时对象返回
5. 临时对象结束,调用临时对象析构函数,释放临时对象堆内存

注意:如果第4步,我们没有定义拷贝构造函数,也就是没有进行深拷贝。那么在进行第5步释放临时对象的heap 空间时,将释放掉的是和目标对象同一块的heap空间。这样当目标对象B作用域结束调用析构函数时,就会产生错误!!
因此,如果赋值运算符返回的是类对象本身,那么一定要重载类的拷贝构造函数(进行深拷贝)!

二:如果赋值运算符返回的是对象的引用
执行结果如下图所示
赋值运算符重载函数 返回引用和返回对象的区别_第2张图片
1 释放对象原来的堆资源
2 重新申请堆空间
3 拷贝源的值到对象的堆空间的值
4 返回源对象的引用
5 结束。
因此,如果赋值运算符返回的是对象引用,那么其不会调用类的拷贝构造函数,这是返回对象和返回引用的主要区别,返回引用的效率明显较高,

如果你把代码换成
(liubei = guanyu) = zhangfei;
返回对象执行效果如下,请仔细调试下,为什么是这样的结果
赋值运算符重载函数 返回引用和返回对象的区别_第3张图片
返回引用执行效果如下
赋值运算符重载函数 返回引用和返回对象的区别_第4张图片

参考文献:
http://blog.chinaunix.net/uid-24876683-id-206802.html

你可能感兴趣的:(C++)