zoukankan      html  css  js  c++  java
  • C++回顾day02---<拷贝构造函数:重点>

    一:补充---无参构造函数(默认无参构造函数)在实例化对象时注意点

    (一)若没有写构造函数,则类会含有一个默认无参构造函数

    (二)若自定义一个构造函数,则类不会提供默认构造函数

    class A
    {
    public:
        A(int a)
        {
            cout << "有参构造函数" << endl;
        }
    
        void getInfo()
        {
            cout << "对象构造完毕" << endl;
        }
    };

    (三)重点:实例化对象时C++允许使用 类名 对象(构造参数)  但是对于无参构造时是无法使用的

    class A
    {
    public:
        A()
        {
            cout << "无参构造函数" << endl;
        }
    
        A(int a)
        {
            cout << "有参构造函数" << endl;
        }
    
        void getInfo()
        {
            cout << "对象构造完毕" << endl;
        }
    };
    
    
    void main()
    {
        A a();    //warning C4930: “A a(void)”: 未调用原型函数(是否是有意用变量定义的?)
    }
    会认为该语句表示声明一个名为a的函数,返回类型是A。

    所以调用无参构造函数可以使用:
        A* a=new A();    
        a->getInfo();

    二:补充---默认拷贝构造函数

    当类中没有定义拷贝构造函数时,编译器默认提供一个默认拷贝构造函数,简单的进行成员变量的值复制(属于浅拷贝)

    三:浅拷贝(默认构造函数)以及对应深拷贝

    默认拷贝构造函数只能完成成员值的简单的复制
    若是类中含有指针成员,在堆上面开辟内存,默认拷贝构造函数,只会做指针值的复制。会导致内存存取错误。

    (一)默认构造函数演示错误产生:第一个对象析构后将堆内存回收,而第二个对象指针依旧指向那块回收的内存。导致读取失败

    class A
    {
    private:
        char* pName;
    public:
        A()
        {
            cout << "A无参构造函数" << endl;
        }
    
        A(char* name)
        {
            cout << "有参构造函数" << endl;
            pName = (char*)malloc(strlen(name) + 1);  //堆上开辟内存
            strcpy(pName, name);
        }
    
        ~A()
        {
            cout << "调用析构函数,释放内存,习惯良好66" << endl;
            delete[] pName;  //进行析构时释放内存
        }
    
        void getInfo()
        {
            cout << "Name:" << pName << endl;
        }
    };
    
    
    void main()
    {
        A* a=new A("ld");
        A b(*a);    //会调用默认构造函数(浅拷贝)
        
        a->getInfo();
        b.getInfo();
    
        delete a;
    
        b.getInfo();
        
        system("pause");
    }

    (二)进行深拷贝处理(自定义拷贝构造函数)

    class A
    {
    private:
        char* pName;
    public:
        A()
        {
            cout << "A无参构造函数" << endl;
        }
    
        A(char* name)
        {
            cout << "有参构造函数" << endl;
            pName = (char*)malloc(strlen(name) + 1);
            strcpy(pName, name);
        }
    
        A(const A& a)
        {
            cout << "调用自定义拷贝构造函数进行深拷贝" << endl;
            pName = (char*)malloc(strlen(a.pName) + 1);    //私有是类间私有,这是同一个类,故可直接使用pName
            strcpy(pName, a.pName);
        }
    ~A()
        {
            cout << "调用析构函数,释放内存,习惯良好66" << endl;
            delete[] pName;
        }
    
        void getInfo()
        {
            cout << "Name:" << pName << endl;
        }
    };
    
    void test()
    {
        A* a = new A("ld");
        A b(*a);    //=不同于拷贝构造函数
    
        a->getInfo();
        b.getInfo();
    
        delete a;  //释放a对象,会调用析构
    
        b.getInfo();
    }  //在函数结尾后释放b对象,调用析构释放内存
    
    void main()
    {
        test();  //进行测试
        
        system("pause");
    }

    四:浅拷贝(=运算符)以及对应深拷贝

    (一)=运算和拷贝构造函数不相关:若是不进行=操作重载,默认是进行浅拷贝

    class A
    {
    private:
        char* pName;
    public:
        A()
        {
            cout << "A无参构造函数" << endl;
        }
    
        A(char* name)
        {
            cout << "有参构造函数" << endl;
            pName = (char*)malloc(strlen(name) + 1);
            strcpy(pName, name);
        }
    
        A(const A& a)
        {
            cout << "调用自定义拷贝构造函数进行深拷贝" << endl;
            pName = (char*)malloc(strlen(a.pName) + 1);    //私有是类间私有,这是同一个类,故可直接使用pName
            strcpy(pName, a.pName);
        }
        ~A()
        {
            cout << "调用析构函数,释放内存,习惯良好66" << endl;
            delete[] pName;
        }
    
        void getInfo()
        {
            cout << "Name:" << pName << endl;
        }
    };
    
    void test()
    {
        A a("ld");
        A b;    //若是A b=a;会调用拷贝构造函数
        b = a;    //会使用=操作符,由于没有重载该运算符,所以是浅拷贝
    }
    
    void main()
    {
        test();
    
        system("pause");
    }

    (二)注意点: A b = a;  调用的是拷贝构造函数  A b;  b=a;调用的是重载运算符=

    (三)重载=运算符,实现深拷贝

        A& operator=(A& a)
        {
            cout << "调用重载运算符进行深拷贝" << endl;
            this->pName = (char*)malloc(strlen(a.pName) + 1);    //私有是类间私有,这是同一个类,故可直接使用pName
            strcpy(this->pName, a.pName);
            return *this;
        }

    五:补充---不存在类的类型变量声明  A a;不是声明,是产生一个对象a,调用无参构造函数

    (一)演示一:A a会调用无参构造函数

    class A
    {
    private:
        char* pName;
    public:
        A()
        {
            cout << "A无参构造函数" << endl;
        }
    
        A(char* name)
        {
            cout << "有参构造函数" << endl;
            pName = (char*)malloc(strlen(name) + 1);
            strcpy(pName, name);
        }
    
        A(const A& a)
        {
            cout << "调用自定义拷贝构造函数进行深拷贝" << endl;
            pName = (char*)malloc(strlen(a.pName) + 1);    //私有是类间私有,这是同一个类,故可直接使用pName
            strcpy(pName, a.pName);
        }
    
    
        ~A()
        {
            cout << "调用析构函数,释放内存,习惯良好66" << endl;
            delete[] pName;
        }
    };
    
    void test()
    {
        cout << "1" << endl;
        A b;    
        cout << "1" << endl;
    }

    (二)演示二:若不存在无参构造函数,则出错(自己写了其他构造函数)

    class A
    {
    private:
        char* pName;
    public:
        A(char* name)
        {
            cout << "有参构造函数" << endl;
            pName = (char*)malloc(strlen(name) + 1);
            strcpy(pName, name);
        }
    
        A(const A& a)
        {
            cout << "调用自定义拷贝构造函数进行深拷贝" << endl;
            pName = (char*)malloc(strlen(a.pName) + 1);    //私有是类间私有,这是同一个类,故可直接使用pName
            strcpy(pName, a.pName);
        }
    
        ~A()
        {
            cout << "调用析构函数,释放内存,习惯良好66" << endl;
            delete[] pName;
        }
    };

    六:补充---匿名对象的去和留

    (一)若是将返回的匿名对象,赋值给另外一个同类型的对象,那么匿名对象会被析构

    1.首次演示:含有一个错误

    class A
    {
    private:
        char* pName;
    public:
        A()
        {
            cout << "无参构造函数" << endl;
            pName = NULL;
            cout << this << endl;
        }
    
        A(char* name)
        {
            cout << "有参构造函数" << endl;
            pName = (char*)malloc(strlen(name) + 1);
            strcpy(pName, name);
    
            cout << this << endl;
        }
    
        A(const A& a)
        {
            cout << "调用自定义拷贝构造函数进行深拷贝" << endl;
            pName = (char*)malloc(strlen(a.pName) + 1);    //私有是类间私有,这是同一个类,故可直接使用pName
            strcpy(pName, a.pName);
    
            cout << this << endl;
        }
    
        void getInfo()
        {
            if (pName != NULL)
            {
                cout << pName << endl;
            }
            else
            {
                cout << "no name" << endl;
            }
        }
    
        ~A()
        {
            cout << "调用析构函数,释放内存,习惯良好66" << endl;
            this->pName;
            cout << this << endl;
            if (pName != NULL)
            {
                delete[] pName;
            }
        }
    };
    
    A getNonObj()
    {
        A a("da");
        //a.getInfo();
        return a;
    }
    
    void test()
    {
        A b;    //同类型对象
        b = getNonObj();    //getNonObj返回一个对象,赋值给另外一个同类型的对象b   这是赋值 =默认是使用浅拷贝 若是需要使用深拷贝,则要重载=运算符
    }  //在这里进行析构时,会报错
    
    void main()
    {
        test();
        system("pause");
    }

    2.原因分析《重点》

    从test方法开始:
    这个程序一共生成3个对象,
    1.在A b这里生成一个无参对象 A1 2.在getNonObj()方法生成一个 A2 ,然后生成一个拷贝构造对象 A3 赋值给b 3.在getNonObj()最后析构局部对象 A2 4.进入test方法最后,按照局部函数入栈顺序,将2中的拷贝构造对象出栈进行析构 A3 5.还剩下最后一个A b最开始的无参对象,会进行析构 A1--->但是这里会报错 原因:
    最开始A1 中pName为NULL,进行b = getNonObj()将b赋值为A3,是浅拷贝,而不是深拷贝
    所以会使A1和A3指向同一个内存,而A3析构时,已经进行内存释放,所以后面A1就会出错 解决方法:
    重载运算符=

    3.正确实现:进行=运算符重载

    class A
    {
    private:
        char* pName;
    public:
        A()
        {
            cout << "无参构造函数" << endl;
            pName = NULL;
            cout << this << endl;
        }
    
        A(char* name)
        {
            cout << "有参构造函数" << endl;
            pName = (char*)malloc(strlen(name) + 1);
            strcpy(pName, name);
    
            cout << this << endl;
        }
    
        A(const A& a)
        {
            cout << "调用自定义拷贝构造函数进行深拷贝" << endl;
            pName = (char*)malloc(strlen(a.pName) + 1);    //私有是类间私有,这是同一个类,故可直接使用pName
            strcpy(pName, a.pName);
    
            cout << this << endl;
        }
    
        A& operator=(const A &a)
        {
            cout << "调用=运算符重载进行深拷贝" << endl;
            pName = (char*)malloc(strlen(a.pName) + 1);    //私有是类间私有,这是同一个类,故可直接使用pName
            strcpy(pName, a.pName);
    
            cout << this << endl;
            return *this;
        }
    
        void getInfo()
        {
            if (pName != NULL)
            {
                cout << pName << endl;
            }
            else
            {
                cout << "no name" << endl;
            }
        }
    
        ~A()
        {
            cout << "调用析构函数,释放内存,习惯良好66" << endl;
            this->pName;
            cout << this << endl;
            if (pName != NULL)
            {
                delete[] pName;
            }
        }
    };
    
    A getNonObj()
    {
        A a("da");
        //a.getInfo();
        return a;
    }
    
    void test()
    {
        A b;    //同类型对象
        b = getNonObj();    //getNonObj返回一个匿名对象,赋值给另外一个同类型的对象b
    
    }
    
    void main()
    {
        test();
        system("pause");
    }
    进行=运算符重载

    (二)若是将返回的匿名对象,来初始化另外一个同类型的对象,那么匿名对象会直接进行拷贝构造对象转成新的对象

    class A
    {
    private:
        char* pName;
    public:
        A()
        {
            cout << "无参构造函数" << endl;
            pName = NULL;
            cout << this << endl;
        }
    
        A(char* name)
        {
            cout << "有参构造函数" << endl;
            pName = (char*)malloc(strlen(name) + 1);
            strcpy(pName, name);
    
            cout << this << endl;
        }
    
        A(const A& a)
        {
            cout << "调用自定义拷贝构造函数进行深拷贝" << endl;
            pName = (char*)malloc(strlen(a.pName) + 1);    //私有是类间私有,这是同一个类,故可直接使用pName
            strcpy(pName, a.pName);
    
            cout << this << endl;
        }
    
        A& operator=(const A &a)
        {
            cout << "调用=运算符重载进行深拷贝" << endl;
            pName = (char*)malloc(strlen(a.pName) + 1);    //私有是类间私有,这是同一个类,故可直接使用pName
            strcpy(pName, a.pName);
    
            cout << this << endl;
            return *this;
        }
    
        void getInfo()
        {
            if (pName != NULL)
            {
                cout << pName << endl;
            }
            else
            {
                cout << "no name" << endl;
            }
        }
    
        ~A()
        {
            cout << "调用析构函数,释放内存,习惯良好66" << endl;
            this->pName;
            cout << this << endl;
            if (pName != NULL)
            {
                delete[] pName;
            }
        }
    };
    
    A getNonObj()
    {
        A a("da");
        //a.getInfo();
        return a;
    }
    
    void test()
    {
        A b = getNonObj();//直接将匿名对象用来初始化同类型对象 会将拷贝构造函数直接设置为这个新的对象
    }
    
    void main()
    {
        test();
        system("pause");
    }

    七:总结--对拷贝构造函数和=操作符重载的区别

    (一)A a = b; 进行初始化,会直接调用拷贝构造函数,不会去找=操作符重载

    (二)A a;   //先生成一个无参对象     a=b;  //会进行赋值操作,调用=操作符重载方法

  • 相关阅读:
    C++概念性总结
    友元函数
    C++指针概念
    Linux下多线程(clone()线程)
    Qt5模块化详细总结
    C++有符号与无符号之间的转换问题
    使用C++test工具做Qt代码静态分析
    QT函数带有外部链接但没有在头文件中声明(QT noreturn属性添加)
    Linux之Docker手动创建Docker容器
    我在思考一个很变态的社会趋向
  • 原文地址:https://www.cnblogs.com/ssyfj/p/10627359.html
Copyright © 2011-2022 走看看