前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++的拷贝构造函数

C++的拷贝构造函数

作者头像
鲜于言悠
发布2024-05-24 10:59:53
400
发布2024-05-24 10:59:53
举报
文章被收录于专栏:c/c++的学习笔记c/c++的学习笔记

前言

类的6个默认成员函数:如果一个类中什么成员都没有,简称为空类。

空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。

默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。


一、拷贝构造函数概念

理解

在现实生活中,可能存在一个与你一样的自己,我们称其为双胞胎。

那在创建对象时,可否创建一个与已存在对象一某一样的新对象呢?

定义

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。

C++拷贝构造函数是一种特殊的构造函数,用于创建对象时,使用一个已有对象的内容来初始化新的对象。它接受一个同类对象作为参数,并按照该对象的数据成员的值来创建新的对象。

拷贝构造函数通常用于以下情况:

  • 在创建对象时,使用同类已有对象的值来初始化新对象。
  • 以值传递方式将对象传递给函数。
  • 以值返回方式从函数返回对象。

拷贝构造函数的定义形式为:

其中,类名是要创建的对象的类名,obj是要拷贝的对象。

拷贝构造函数的工作原理是将obj的数据成员的值复制给新创建的对象。这意味着新对象的数据成员会与原对象具有相同的值,但是它们是独立的,改变其中一个对象的数据成员的值不会影响另一个对象的数据成员。

如果没有显式定义拷贝构造函数,编译器会提供一个默认的拷贝构造函数。默认的拷贝构造函数执行的是浅拷贝,即简单地将原对象的值复制给新对象的数据成员。如果类中包含指针类型的数据成员,需要自己定义拷贝构造函数,进行深拷贝,确保指针指向的对象也被复制。

注意,拷贝构造函数是类成员函数,通常定义在类的公有部分。拷贝构造函数是通过对象名来调用的,而不是通过函数名来调用。

二、拷贝构造函数的特征

拷贝构造函数也是特殊的成员函数,其特征如下:

  1. 拷贝构造函数是构造函数的一个重载形式。
  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。
  1. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。 和构造函数不一样,构造函数内置类型不会初始化,拷贝构造函数会初始化

注意:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定义类型是调用其拷贝构造函数完成拷贝的。

  1. 编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,还需要自己显式实现吗? 当然像日期类这样的类是没必要的。那么下面的类呢?验证一下试试?

注意:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数是一定要写的,否则就是浅拷贝。

  1. 拷贝构造函数典型调用场景:
    • 使用已存在对象创建新对象
    • 函数参数类型为类类型对象
    • 函数返回值类型为类类型对象

为了提高程序效率,一般对象传参时,尽量使用引用类型,返回时根据实际场景,能用引用尽量使用引用。

三、注意要点

写法

除了下面这种写法外

我们还可以写成,这种写法也是拷贝构造

实践

  • 如果没有管理资源,一般情况下不需要写拷贝构造函数,默认生成的拷贝构造函数就可以。如Date(日期类)
  • 如果都是自定义类型成员,内置类型成员没有指向资源,也类似默认生成的拷贝构造函数就可以。如MyQueue
  • 一般情况下,不需要显示写析构函数,就不需要写拷贝构造函数
  • 如果内部有指针或者一些值指向资源,需要显示写析构释放,通常就需要显示写构造函数完成深拷贝。如:Stack Queue List

传址返回与引用返回的区别

关于下面代码的展示,VS2022编译器可能显示不出来,因为编译器等级比较高,像下面的情况,编译器会自行优化,使代码运行效率更高,致使本来的结果显示不出来。

传址返回

传址返回会生成Date d 的临时拷贝进行返回

引用返回

引用返回会直接返回Date d的地址,而不会进入临时拷贝

出了函数作用域之后会调用析构函数,致使结果为-1,此时的ref类似野指针

依次类推,我们再定义一个fx()函数,在fx()函数的空间里存放一些变量,ret空间里的内容会被fx()函数里的内容给覆盖

当出了作用域,返回对象还在没有析构,那就可以用引用返回,减少拷贝,比如用static修饰

传值返回和传址返回的对比

Date operator=运用的下篇文章赋值运算符重载,可以看到传值和传址在遇到不同问题时有不同的表现,如下,在运算符重载的问题下,传址调用比传值调用的效率更高

总结

返回对象是一个局部对象或临时对象,出了当前func函数作用域,就析构销毁了,那么不能用引用返回,用引用返回时存在风险的,因为引用对象在func函数栈帧已经销毁了

虽然引用返回可以减少一次拷贝,但是出了函数作用域,返回对象还在,才能用引用返回

即下述情况

  • 返回对象生命周期到了,会析构,传值返回
  • 返回对象生命周期没到,不会析构,传引用返回

测试

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-05-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、拷贝构造函数概念
    • 理解
      • 定义
      • 二、拷贝构造函数的特征
      • 三、注意要点
        • 写法
          • 实践
            • 传址返回与引用返回的区别
              • 传址返回
              • 引用返回
            • 传值返回和传址返回的对比
              • 总结
                • 测试
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档