• 赋值运算,拷贝运算,运算符重载


    赋值运算与拷贝运算的区别

    如果对象在申明之后进行赋值运算,我们称之为赋值运算。例如:
    class1 A("af"); class1 B;
    B=A;
    此时实际调用的类的缺省赋值函数B.operator=(A);

    如果对象在申明的同时马上进行初始化操作,则称之为拷贝运算。例如:
    class1 A("af"); class1 B=A;
    此时其实际调用的是B(A)这样的浅拷贝操作。

    C++与C#对象的内存分配方式的不同

    在C++中,对象的实例在编译的时候,就需要为其分配内存大小,因此,系统都是在stack上为其分配内存的。

    在C#中,所有类都是reference type,要创建类的实体,必须通过new在heap上为其分配空间,同时返回在stack上指向其地址的reference.

    C++中赋值操作的内存情况

    class A
    {
    public:
        A()
        {
        }
        A(int id,char *t_name)
        {
        _id=id;
        name=new char[strlen(t_name)+1];
        strcpy(name,t_name);
        }
        private:
            char *username;
            int _id;
    }
    
    int main()
    {
    A a(1,"herengang");
    A b;
    b=a; }

    b=a执行的是缺省的赋值运算。所谓缺省的赋值运算,是指对象中的所有位于stack中的域,进行相应的复制。但是,如果对象有位于heap上的域的话,其不会为拷贝对象分配heap上的空间,而只是指向相同的heap上的同一个地址。
    执行b=a这样的缺省的赋值运算后,其内存分配如下

    因此,对于缺省的赋值运算,如果对象域内没有heap上的空间,其不会产生任何问题。但是,如果对象域内需要申请heap上的空间,那么在析构对象的时候,就会连续两次释放heap上的同一块内存区域,从而导致异常。

    解决办法--重载(overload)赋值运算符

    class A
    {
    public:
    
        A()
        {
        }
        A(int id,char *t_name)
        {
            _id=id;
            name=new char[strlen(t_name)+1];
            strcpy(name,t_name);
        }
        
        A& operator =(A& a)
    //注意:此处一定要返回对象的引用,否则返回后其值立即消失!
        {
                if(name!=NULL)
                    delete name;
            this->_id=a._id;
            int len=strlen(a.name);
            name=new char[len+1];
            strcpy(name,a.name);
            return *this;
        }
    
        ~A()
        {
            cout<<"~destructor"<<endl;
            delete name;
        }
    
        int _id;
        char *name;
    };
    
    int main()
    {
     A a(1,"herengang");
     A b;
     b=a;
    }

    如何重载赋值运算符

    法I:返回类对象的引用

    A& A::operaton=(A &a)
    {
            if(this==&a)//  考虑a=a这样的操作。
                return *this;
            if(username!=NULL) //释放自身的堆空间
                delete username;
            _id=a._id;
            username=new char[strlen(a.username)+1];
            if(username!=NULL)
                strcpy(username,a.usernam);
            return *this;    
    }

    其过程如下:
                       1 释放掉目标对象原来占有的堆空间
                       2 申请一块新的堆内存
                       3 将源对象的堆内存的值深度拷贝给新的堆内存
                       4 返回目标对象的引用
                       5 结束。

    法II:返回类对象本身

    其过程是这样的:
                           1 释放目标对象原来的堆资源
                           2 重新申请堆空间
                           3 拷贝源的值到目标对象的堆空间
                           4 调用临时对象拷贝构造函数创建临时对象,将临时对象返回(因为函数返回时,会清空栈,在栈中的目标对象也会被清,所以需要临时对象)
                           5.临时对象结束,调用临时对象析构函数,释放临时对象堆内存
    如果第4步,我们没有overload 拷贝函数,也就是没有进行深拷贝。那么在进行第5步释放临时对象的heap 空间时,将释放掉的是和目标对象同一块的heap空间。这样当目标对象B作用域结束调用析构函数时,就会产生错误!
    因此,如果赋值运算符返回的是类对象本身,那么一定要overload 类的拷贝函数(进行深拷贝)!

    法III:返回void

    如果这样的话,他将不支持客户代买中的链式赋值 ,例如a=b=c will be prohibited!

    拷贝构造函数

    赋值函数最好是对象的引用, 而拷贝函数不需要返回任何。

    同时,赋值函数首先要释放掉对象自身的堆空间,然后进行其他的operation。而拷贝函数不需要如此,因为对象此时还没有分配堆空间。

    A::A(A &a)
    {
    
        int len=strlen(a.m_username);
        this->m_username=new char[len+2];
        strcpy(m_username,a.m_username);
        strcat(m_username,"f");
        printf("
    deep copy function");
    }

    运算符的重载

    返回对象本身。因为如果返回引用,会导致擦操作数被意外修改,比如a+b=c,会将c赋给a

    class Complex //复数类
    {
    private://私有
    double real;//实数
    double imag;//虚数
    public:
            Complex(double real=0,double imag=0)
            {
    this->real=real;
    this->imag=imag;
            }
            Complex operator+(int x);
    };
    
    Complex Complex::operator+(int x)
    {
    return Complex(real+x,imag);
    }
    
    int main()
    {
        Complex com1(5,10),total;
        total=com1+5;
    
    return0;
    }

  • 相关阅读:
    170601、单例模式的三种水平代码(第三种最佳)
    解决打开pycharm有带图片md文件卡死问题
    Dockerfile 操作
    Docker 命令大全
    MAC
    mac 搭建selenium与ChromeDriver环境
    Mac进行 usr/bin 目录下修改权限问题,operation not permitted
    pytest文档6-fixture之yield实现teardown
    pytest文档5-fixture之conftest.py
    pytest文档4-测试用例setup和teardown
  • 原文地址:https://www.cnblogs.com/qionglouyuyu/p/4175444.html
Copyright © 2020-2023  润新知