zoukankan      html  css  js  c++  java
  • 拷贝构造 赋值构造 浅拷贝 深拷贝

    拷贝构造函数

    拷贝构造是在传入一个类的实例作为参数创建新的类的时候触发的

    class ctest
    {
    public:
        ctest(ctest& t)
        {
            cout << "ctest(ctest& t)" << endl;
        }
    };
    

    也可以为参数增加const修饰防止修改。触发拷贝构造的情况一般有两种

    ctest a;
    ctest b(a);
    ctest c = a;
    

    b和c都会调用拷贝构造,b很好理解,直接传递了一个实例a,所以从函数的参数列表对应,也是应该调用拷贝构造。对于c可能有人认为是赋值构造,实际上是错误的,因为赋值的时候c是没创建的,相当于用a初始化创建c,所以还是拷贝构造。并且赋值构造并不能算作构造函数,它有返回值,赋值构造可以叫做赋值函数。

    注意

    拷贝构造函数必须是传入的引用或者指针也可以,但是不可以传递形参,现在的编译器已经可以直接识别错误了。因为如果传递形参,那么在形参传递过程种需要创建局部变量,那么又会调用赋值构造,就会导致死循环创建。

    赋值构造

    赋值构造相当于重载了操作符等号(=)

    class ctest
    {
    public:
        ctest& operator = (ctest& t)
        {
            return *this;
        }
    };
    

    赋值构造函数必须是返回自己的引用,因为有连等的操作,可以不返回,但是会在连等的情况下出问题,按照C++的等号操作符的规则,是需要返回自己的引用

    赋值构造在已存在的实例赋值操作时触发,如果实例是在创建的时候调用等号,就会调用上面的拷贝构造

    ctest a;
    ctest b;
    b = a;
    

    注意与上面的示例区别

    浅拷贝

    对于有指针类型成员的类,拷贝构造和赋值构造的时候需要注意,因为如果我们不重载拷贝构造或者赋值构造,类是有默认的函数的,它的操作就是直接赋值,那么就会导致两个类的指针保存了同一个值,也就是指向了同一块空间,这样不管在析构还是在使用的时候都会引发问题

    class ctest
    {
    public:
        ctest()
        {
            m_data = NULL;
        }
        ~ctest()
        {
            if (m_data != NULL)
            {
                delete[] m_data;
                m_data = NULL;
            }
        }
        char* m_data;
    };
    void test()
    {
        ctest a;
        a.m_data = new char[10]{ 'a','b' };
    
        //下面这两个类都会在析构的时候报错
        ctest b(a);
        ctest c;
        c = a;
    }
    int main()
    {
        test();
        return 0;
    }
    

    在test函数种,类a申请了内存,并且做了初始化,然而b和c都在构造和赋值的时候让自己内部的m_data值等于了a的m_data。那么指向同一块内存的多个指针在析构的时候进行多次释放,导致崩溃。这种情况下需要深拷贝

    深拷贝

    深拷贝就是在拷贝和复制的时候进行一个额外的操作,防止出现多个类实例公用一块空间而导致不可预料的问题

    class ctest
    {
    public:
        ctest()
        {
            m_data = NULL;
        }
        ctest(const char * p)
        {
            if (p != NULL)
            {
                m_data = new char[strlen(p) + 1]();
                strcpy(m_data, p);
            }
        }
        ctest(const ctest& t)
        {
            if (t.m_data != NULL)
            {
                m_data = new char[strlen(t.m_data) + 1]();
                strcpy(m_data, t.m_data);
            }
        }
        ctest& operator=(const ctest& t)
        {
            if (this != &t && t.m_data != NULL)
            {
                m_data = new char[strlen(t.m_data) + 1]();
                strcpy(m_data, t.m_data);
            }
            return *this;
        }
        ~ctest()
        {
            if (m_data != NULL)
            {
                delete[] m_data;
                m_data = NULL;
            }
        }
    private:
        char* m_data;
    };
    void test()
    {
        ctest a("abc");
        ctest b(a);
        ctest c;
        c = a;
    }
    int main()
    {
        test();
        return 0;
    }
    

    上面就是实现了一个简单的string类,其中就用到了深拷贝,在构造和赋值的时候,都会为自己的类重新申请一块空间保存传递进来参数的数据,而不是直接赋值,这样就可以避免在析构的时候对同一块内存多次释放的问题。

    版权声明:本文版权归作者所有,如需转载,请标明出处

  • 相关阅读:
    Kafka 1.0.0集群安装
    java实现以docx格式导出
    基于java处理.docx格式的word合并
    基于java 合并.doc和docx格式的Word文件
    Docker版本Jenkins的使用
    Codeforces 1243 D 0-1 MST
    Public model for matrix
    Codeforces 1220 E Tourism
    Codeforces 1221 G Graph And Numbers
    Codeforces 1221 F Choose a Square
  • 原文地址:https://www.cnblogs.com/studywithallofyou/p/14557966.html
Copyright © 2011-2022 走看看