c++__拷贝构造函数

定义

拷贝构造函数又被叫做复制构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构建及初始化。

背景

在C++中,下面三种对象需要调用拷贝构造函数(有时也称“复制构造函数”):

  1.  一个对象作为函数参数,以值传递的方式传入函数体
  2.  一个对象作为函数返回值,以值传递的方式从函数返回;
  3.  一个对象用于给另外一个对象进行初始化(常称为赋值初始化);

如果在前两种情况不使用拷贝构造函数的时候,就会导致一个指针指向已经被删除的内存空间。对于第三种情况来说,初始化和赋值的不同含义是拷贝构造函数调用的原因。事实上,拷贝构造函数是由普通构造函数和赋值操作符共同实现的。

特性

  1.  拷贝构造函数是构造函数的一个重载形式。
  2.  拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。
    #include<iostream>
    
    using namespace std;
    
    class Date{
    public:
        Date(int year = 1900, int month = 1, int day = 1){
            _year = year;
            _month = month;
            _day = day;
        }
        Date(const Date& d){
            _year = d._year;
            _month = d._month;
            _day = d._day;
        }
    private:
        int _year;
        int _month;
        int _day;
    
    };
    
    int main() {
        Date d1;
        Date d2(d1);
        return 0;
    }

  3. 3.若未显示定义拷贝构造函数,系统会生成默认的拷贝构造函数。

浅拷贝和深拷贝:

所谓浅拷贝,指的是在对象复制时,只对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。

大多情况下“浅拷贝”已经能很好地工作了,但是一旦对象存在了动态成员,那么浅拷贝就会出问题了,如下:

class Date{
public:
    Date(int year = 1900, int month = 1, int day = 1){
        _year = year;
        _month = month;
        _day = day;
    } 
private:
    int _year;
    int _month;
    int _day;
};
int main() {
    Date d1(2001,29,1);
    // 这里d2调用的默认拷贝构造完成拷贝,d2和d1的值也是一样的。
    //此时调用浅拷贝完全可以解决拷贝问题,但当加入动态成员变量时,浅拷贝就不能很好的解决问题
    Date d2(d1);
    return 0;
}
  1. using namespace std;
    class Rect{
    public:
        Rect(){
            p = new int(50);
        }
    
        ~Rect(){
            assert(p!=NULL);
            delete p;
        }
    private:
        int width;
        int height;
        int *p;
    };
    int main(){
        Rect rect1;
        Rect rect2(rect1);
        return 0;
    }

    第二段代码在运行定义rect1时,由于构造函数有一个动态的分配语句,在使用rect2拷贝rect1时,由于进行的是浅拷贝,只是将值赋值给了rect2,两个指针指向的就是同一块内存,在调用析构函数的时候,两个对象调用两次析构函数对同一块地址空间进行销毁,这就是出错的原因。

深拷贝:

每个对象共同拥有自己的资源,必须显式提供拷贝构造函数和赋值运算符。

class Rect{
public:
    Rect(){
        p = new int(50);
    }

    Rect(const Rect& r){
        width = r.width;
        height = r.height;
        p = new int(50);
        *p = *(r.p);
    }
    ~Rect(){
        assert(p!=NULL);
        delete p;
    }
private:
    int width;
    int height;
    int *p;
};
int main(){
    Rect rect1;
    Rect rect2(rect1);
    return 0;
}

此时的rect1和rect2各自指向一块内存空间,不会发生上述的情况

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值