C++学习-类和对象(三)

拷贝构造

创建对象时使用同类对象来进行初始化,这时所用的构造函数称为拷贝构造函数(Copy Constructor),拷贝构造函数是特殊的构造函数

就是使用一个已经存在的对象去创建一个新的对象。新的对象是旧的对象的一份拷贝。

  1. 拷贝构造函数其实是一个构造函数的重载。
  2. 拷贝构造函数的参数必须使用引用传参,使用传值方式会引发无穷递归调用。
  3. 若未显示定义,系统会默认缺省的拷贝构造函数。默认生成(浅拷贝:一个字节一个字节拷贝)依次拷贝类成员进行初始化。
//使用默认的拷贝构造(浅拷贝)
#include<iostream>
using namespace std;
class Data

{
    public:



        //带参的缺省的构造函数

        Data(int year=1900,int month=1,int day=1)
        {
            _year=year;
            _month=month;
            _day=day;

        }

        void Display()
        {
            cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
        }
        ~Data()//析构函数
        {

        }


    private:
        int _year;
        int _month;
        int _day;

};
int main()
{


    Data d1(2018,1,1);//调用构造函数

    Data d2(d1);//调用拷贝构造函数
    //Data d2=d1 和上面是等价的

    d1.Display();
    d2.Display();
    return 0;

}
[zyc@localhost lession_class]$ ./a.out 
2018-1-1
2018-1-1

结果分析:

利用d1.我们拷贝构造了一个对象d2。


默认拷贝构造的缺陷

来看下面例子

#include<iostream>
#include <stdlib.h>
using namespace std;
class Array
{
    public:
        //构造函数
        Array()
        {
            cout<<"Array()"<<endl;
            _ptr=(int *)malloc(2*sizeof(int));

        }

        //这里的析构函数需要完成清理工作(释放空间)

        ~Array()
        {


                cout<<"~Array()"<<endl;
                free(_ptr);
                _ptr=NULL;

        }


    private:
        int *_ptr;

};
int main()
{
    Array ptr;
    return 0;

}

编译通过,调用一次构造函数,一次析构函数


[zyc@localhost lession_class]$ ./a.out 
Array()
~Array()

类在我们没有定义拷贝构造函数的时候,会默认定义默认拷贝构造函数,也就是说可以直接用同类型的类间可以相互赋值、初始化:

int main()
{
    Array p1;
    Array p2=p1;
    return 0;

}

这个时候,编译器机会报错,原因就是因为同一块空间被释放了两次

这里写图片描述
这里写图片描述

类的默认拷贝构造函数只会用被拷贝类的成员的 值 为拷贝类简单初始化,也就是说二者的p指针指向的内存空间是一致的。以前面Array可以知道,编译器为我们默认定义的拷贝构造函数为:

Array(const Array& Array)
{
    p1 = Array.p1;
    pp2 = Array.p1;      //两个类的p指针指向的地址一致。
}

main函数将要退出时,拷贝类p2的析构函数先得到执行,它把自身p指向的堆空间释放了;接下来,p1的析构函数得到调用,被拷贝类p1的析构函数得到调用,它同样要去析构自身的p指向指向的堆空间,但是该空间和p2类中p指向的空间一样,造成重复释放,程序运行崩溃。

这里写图片描述

为了解决这种问题,我们可以使用自定义拷贝构造函数,里面用深度拷贝的方式为拷贝类初始化

深拷贝原理

这里写图片描述

关于深拷贝后面再介绍。

自定义拷贝构造函数,也可以定义成简单的值拷贝,即浅拷贝。

class Data

{
    public:



        //带参的缺省的构造函数

        Data(int year=1900,int month=1,int day=1)
        {
            _year=year;
            _month=month;
            _day=day;

        }
        Data(const  Data& d)//拷贝构造函数,这里必须使用传引用
        {
            this->_year=d._year;
            this->_month=d._month;
            this->_day=d._day;
        }
        void Display()
        {
            cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
        }
        ~Data()//析构函数
        {

        }


    private:
        int _year;
        int _month;
        int _day;

};

拷贝构造函数 需要注意的问题

拷贝构造函数的参数必须使用引用传参,使用传值方式会引发无穷递归调用。
传引用,否则无限递归

举例:假设是传参时使用传值方式。


class Data
{
    public:
        //构造函数
        Data()
        {
            cout<<"Data()"<<endl;

        }
        //拷贝构造函数,以传值方式
        Data(const Data d )
        {
            cout<<"Data(const Data &d)"<<endl;
        }
        ~Data()
        {
                cout<<"~Data()"<<endl;
        }
    private:
        int a; 

};
int main()
{
    Data d1;
    Data d2=d1;
    return 0;

}

运行结果:会提示报错信息。编不过

[zyc@localhost lession_class]$ g++ tmp.cpp -g
tmp.cpp:21: error: invalid constructor; you probably meant ‘Data (const Data&)’

原因:
这里写图片描述

将传值应用更改成传引用。

Data(const Data &d )

运行结果

[zyc@localhost lession_class]$ ./a.out 
Data()
Data(const Data &d)
~Data()
~Data()

猜你喜欢

转载自blog.csdn.net/zgege/article/details/81050539