本系列文章主要介绍 C++ 编程语言中类对象的赋值操作、复制操作,以及两者之间的区别,另外还会介绍“深拷贝”与“浅拷贝”的相关知识。

本文为系列文章的第三篇,主要介绍 C++ 编程语言中的“深拷贝”和“浅拷贝”,以及赋值运算符的重载、拷贝构造函数的重载的相关知识。

1 浅拷贝

1.1 What

浅拷贝:当进行对象拷贝时,只拷贝类中位于 stack 域中的内容,而不会拷贝 heap 域中的内容。

例如,使用类的默认的赋值运算符“=”,或默认的拷贝构造函数时,进行的对象拷贝都属于浅拷贝。这也说明,“浅拷贝”与使用哪种方式(赋值运算符或是拷贝构造函数)进行对象拷贝无关。

1.2 问题

浅拷贝会有一个问题,当类中存在指针成员变量时,进行浅拷贝后,目标对象与源对象的该指针成员变量将会指向同一块 heap 内存区域(而非每个对象单独占用一块内存区域),这就可能导致由于共用该段内存区域而产生内存覆盖、重复释放内存等问题。详情可参考本系列文章第一篇文章的相关内容。

所以,针对带有指针的类对象的拷贝操作,正确的做法是:使两个对象的指针各自指向不同的内存区域,即在拷贝时不是简单地拷贝指针,而是将指针指向的内存中的每一个元素都进行拷贝,由此也就引出了“深拷贝”的概念。

2 深拷贝

深拷贝:当进行对象拷贝时,将对象位于 stack 域和 heap 域中的数据都进行拷贝。

前面也提到了,类默认提供的赋值运算符或拷贝构造函数,进行的都是浅拷贝,所以,为了实现对象的深拷贝,需要对赋值运算符或拷贝构造函数进行重载,以达到深拷贝的目的。

2.1 赋值运算符的重载

这里展示一段重载赋值运算符的示例代码,内容如下:

    // 重载赋值运算符ClassA& operaton=(const ClassA& obj){// 适应自赋值(obj = obj)操作if (this == &obj){return *this;}// 新建 heap 空间int iLength = strlen(str.m_pData);char* pTemp = new char[iLength + 1];// 新建 heap 空间成功后,再释放掉已有的 heap 空间// 保证异常安全性if (m_pszName != NULL){delete []m_pszName;m_pszName = NULL;}m_pszName = pTemp;// 拷贝 heap 空间的内容strcpy(m_pszName, obj.m_pszName);// 拷贝 stack 域的值m_nId = obj.m_nId;return *this;}private:int m_nId;char* m_pszName;

针对上面的赋值运算符重载函数,说明如下:

  1. 需要将函数返回值的类型声明为类的引用,同时函数返回实例自身的引用(*this)——只有返回一个引用,才可以允许连续赋值,如 a = b = c;
  2. 需要将入参的类型声明为常量引用(const 类名& 实例名),避免函数入参的拷贝构造函数调用,提高代码效率;
  3. 需要考虑自赋值情况;
  4. 需要释放实例自身已有的内存,避免内存泄漏;
  5. 需要考虑异常安全性,避免申请内存(new char)失败后,实例中的指针变为空指针,因此需要先执行申请内存操作,内存申请成功后,再释放实例的 heap 空间。

2.2 拷贝构造函数的重载

这里展示一段重载拷贝构造函数的示例代码,内容如下:

    // 重载拷贝构造函数,重载后的拷贝构造函数支持深拷贝ClassA(ClassA &obj){// 拷贝 stack 域的值m_nId = obj.m_nId;// 新建 heap 空间m_pszName = new char[strlen(obj.m_pszName) + 1];// 拷贝 heap 空间的内容if (m_pszName != NULL){strcpy(m_pszName, obj.m_pszName);}}private:int m_nId;char* m_pszName;

2.3 总结

从上述两个示例代码可以看出,支持深拷贝的重载赋值运算符和重载拷贝构造函数相似,但两者也存在以下区别:

  • 重载赋值运算符函数的返回值需要是对象的引用,以进行链式赋值(obj3 = obj2 = obj1);而重载拷贝构造函数因为属于构造函数的一种,所以不需要返回值;
  • 重载赋值运算符函数要释放掉对象自身的 heap 空间(如果存在的话),以避免内存泄漏;而重载拷贝构造函数无需如此,因为拷贝构造函数函数是在创建(并初始化)对象时调用的,对象此时还没有分配 heap 空间;
  • 如果在重载赋值运算符和重载拷贝构造函数都可以解决问题时,建议选择重载拷贝构造函数,因为后者貌似坑少一些:)。

C++编程语言中类对象的赋值与复制介绍(三)相关推荐

  1. 对象的赋值和复制(转)

    一.对象的赋值和复制 1.对象的赋值 如果对一个类定义了两个或多个对象,则这些同类的对象之间可以互相赋值,或者说,一个对象的值可以赋给另一个同类的对象.这里所指的对象的值是指对象中所有数据成员的值. ...

  2. C++对象的赋值和复制

    C++对象的赋值 1.1对象之间的赋值是用"="运算符来实现的,"="在c++中扩展为重载运算符来实现对象间的赋值. t1=t2; 1.2对象赋值是对数据成员的 ...

  3. python复制列表元素_Python学习教程:Python列表赋值,复制,深拷贝及5种浅拷贝详解...

    Python学习教程:Python列表赋值,复制,深拷贝及5种浅拷贝详解 概述 在列表复制这个问题,看似简单的复制却有着许多的学问,尤其是对新手来说,理所当然的事情却并不如意,比如列表的赋值.复制.浅 ...

  4. java 对象复制 反射_利用Java反射机制实现对象相同字段的复制操作

    一.如何实现不同类型对象之间的复制问题? 1.为什么会有这个问题? 近来在进行一个项目开发的时候,为了隐藏后端数据库表结构.同时也为了配合给前端一个更友好的API接口文档(swagger API文档) ...

  5. java两个对象赋值_一起学Java(二十六)----- 对象之间赋值

    不积跬步,无以至千里:不积小流,无以成江海. Java语言基础 Java对象之间赋值 赋值是用等号运算符" = "进行的,在对对象进行"赋值"时,实际就是将句柄 ...

  6. 将对象的属性值复制到另一个对象中

    将对象的属性值复制到另一个对象中 /**** 将第一个对象的属性值复制到第二个对象中* @param <T> 第一个对象* @param <R> 第二个对象*/ class H ...

  7. Java中类对象为空是什么意思?

    Java中类对象为空是什么意思? 类对象为空并不等于该对象某一属性或多个属性为空,哪怕该对象所有属性为空也不能说明该对象就为空.一个类对象是否为空和它的属性没有关系. 类对象为空,要么该对象赋值为空, ...

  8. 通过反射为对象属性赋值

    /// <summary>/// 通过反射为对象属性赋值/// </summary>/// <typeparam name="T">类型参数&l ...

  9. C++中对象的赋值拷贝构造函数

    目录 1.对象与对象之间的赋值. 下面给出代码说明赋值语句 对象赋值的限制和特点 2.拷贝构造函数 拷贝构造函数的特点 自定义的拷贝构造函数的代码及运行结果 默认拷贝构造函数 调用拷贝构造函数的3种情 ...

  10. 1.19(对象类型判断、复制、in、遍历;深拷贝与浅拷贝;字符串的遍历接口、模板字符串、字符串扩展方法)

    1.19(对象类型判断.复制.in.遍历;深浅拷贝;字符串的遍历接口.模板字符串.unicode.字符串扩展方法) 一.对象 1.属性简洁表示法与属性名表达式 let name = "wuy ...

最新文章

  1. 李飞飞:人工智能应用广泛 但场景理解不如2岁孩子
  2. Oracle11g数据库在win7系统上的安装教程
  3. mysql数据库导入外部数据乱码么_解决MySQL数据库导入导出数据乱码的问题
  4. Linux 自学大全,16张思维导图!
  5. 分布式实物实现方式_这是您完成实物产品设计任务的方式
  6. 数据结构杂谈(五)——栈
  7. python 数据库查询返回list或tuple
  8. android 自动打开qq,qq自动发消息脚本
  9. 小米路由器3 变砖 ttl 救砖,刷入padavan
  10. PreparedStatement 防止 SQL 注入原理
  11. 马克思主义基本原理概论第一章笔记
  12. Cortex-M0+电源管理
  13. openLayers 学习思维导图
  14. LTE(4G) - NR(5G) EPS承载
  15. Kafka学习笔记1
  16. 大文件MD5计算 C语言 (从OpenSSL库中分离算法:三)
  17. QT翻金币小游戏实现(三)
  18. 小米手机混淆升级崩溃记录与解决
  19. 【新】CSDN文章一键打印、输出PDF(自动阅读全文、全清爽模式)
  20. 项目 - 基于Docker Swarm的高可用Web集群

热门文章

  1. Linux下打包qt程序,可以发布到一台纯净的linux发行版系统上
  2. 你已经是一个成熟的码农了,这些思维习惯你要有!
  3. JavaScript的apply和call方法及其区别
  4. linux 修改自动联网的配置说明
  5. VMware vSphere ESX 迁移到 ESXI 指南
  6. Windows说明Linux分区和挂载点
  7. 全面启动远程医疗行业
  8. ubuntu安装 Samba实现局域网文件共享 win10访问
  9. PHP设计模式——迭代器模式
  10. Linux局域网文件分享系统Samba