C++——类和对象之拷贝构造

拷贝构造

本章思维导图:

在这里插入图片描述

注:本章思维导图对应的xmind文件和.png文件都已同步上传到”资源“


如果我们想要用一个已经存在的对象实例化一个与之完全相同的对象,怎么做呢?

C++提供了一个简单的方法——拷贝构造

拷贝构造是C++类里面默认成员函数之一

1.1 拷贝构造的声明

在这里插入图片描述

  • 拷贝函数是构造函数的重载
  • 拷贝函数没有返回值
  • 只有一个形参,该形参必须是类类型的引用,且最好由const修饰

例如,对于Date类的拷贝构造,应该声明为:

Date(const Date& d);

如果形参不是引用类型,那么就会报错:

“Date”: 非法的复制构造函数: 第一个参数不应是“Date”

我们来进行分析:

在这里插入图片描述

所以我们才说:形参必须是类类型的引用

1.2 拷贝构造的定义

在这里插入图片描述

要知道如何正确的定义拷贝构造,就需要先对浅拷贝和深拷贝有简单的了解:

1.2.1 浅拷贝

  • 浅拷贝又称值拷贝
  • 浅拷贝只是对成员变量值的简单复制,而不是复制指向的动态分配的资源(如堆内存)
  • 原对象和拷贝对象将共享相同的资源

例如,对于Date类的拷贝构造:

Date(int year = 1, int month = 1, int day = 1)
{
    //只是对成员变量值的简单复制
    _year = year;
    _month = month;
    _day = day;
}

而如果我们将Stack类的拷贝构造写成浅拷贝:

Stack(const Stack& st)
{
    _a = st._a;
    _capacity = st._capacity;
    _top = st._top;
}

那么代码 _a = st._a就会带来极大的危险:

  • 这是对两个指针进行简单的值拷贝,即让这两个指针的值相同,即指向相同的内容。如图:

    在这里插入图片描述

  • 那么,如果在这种情况下**,调用析构函数就会出现错误**:

    ~Stack()
    {
        free(_a);
        _capacity = _top = 0;
    }
    int main()
    {
    	Stack st1;
    	Stack st2(st1);
    
    	return 0;
    }
    

  • 这是因为,_ast._a这两个指针都指向了相同的区域,当对象st1调用析构函数后,其指向的空间就被销毁了,成了野指针,当st2再次调用析构函数时,就会造成对野指针的销毁,而free是不能对野指针进行操作的,因此会报错。

因此,当涉及到指针类型的拷贝时,仅靠浅拷贝是不够的,这就我们的需要深拷贝了。

1.2.2 深拷贝

  • 深拷贝又称址拷贝
  • 相较于浅拷贝只是对成员变量值的简单赋值,深拷贝会复制对象的成员变量以及指向的资源,包括指针指向的数据
  • 这确保了原对象和拷贝对象拥有彼此独立但内容相同的资源副本

例如,Stack类的拷贝构造的正确写法为:

Stack(const Stack& st)
{
    //址拷贝
    _a = (int*)malloc(sizeof(int) * st._capacity);	//开辟相同大小的空间
    memcpy(_a, st._a, st._capacity * sizeof(int));	//使新空间的内容和原来的一样

    _capacity = st._capacity;
    _top = st._top;
}

可以通过调试来检验正确性:

在这里插入图片描述

可以看到st1._ast2._a虽然内容相同,但地址不同,说明结果正确。


因此,当定义拷贝构造时,就必须考虑一个问题:

  • 拷贝时涉及资源空间的拷贝(对指针指向空间的拷贝),就一定要用深拷贝(址拷贝)

  • 如果只是简单的复制操作,那就进行浅拷贝(值拷贝)

1.3 默认拷贝构造

在这里插入图片描述

因为拷贝构造是C++类里面的默认成员函数,因此,如果用户不自定义拷贝构造,系统就会自动生成调用

那么,系统自动生成的是浅拷贝还是深拷贝呢?

让我们用Stack类一试便知:

在这里插入图片描述

可以看到,st1._ast2._a不仅内容相同,且地址相同。显而易见:

系统默认生成的拷贝构造是浅拷贝

  • 对于内置类型,只进行赋值操作
  • 对于自定义类型,调用它的拷贝构造

1.4 拷贝构造的必要性

在这里插入图片描述

必须自定义拷贝构造的情况:

  • Stack
  • 涉及到对指针指向空间资源的拷贝时,必须自定义拷贝构造,形成深拷贝。使新对象指针指向的空间和原空间独立且相同
  • 如果不用深拷贝,就会造成free野指针的情况,使程序崩溃

可以不自定义拷贝构造的情况:

  • Date
  • 如果只是对成员变量值的简单复制,那么用浅拷贝即可。可以不用自定义拷贝构造,直接用系统自动生成的即可。
  • 如果类的成员变量都是自定义类型,那也可以直接用自动生成的拷贝构造

下一章,我们将讲C++类里面运算符重载等相关知识。
如果觉得本篇对你有所帮助或者对以后的内容感兴趣,不妨关注专栏👉C++教程
请添加图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Forward♞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值