【C++指南】类和对象(四):类的默认成员函数——全面剖析 : 拷贝构造函数

 引言

拷贝构造函数是C++中一个重要的特性,它允许一个对象通过另一个已创建好的同类型对象来初始化

了解拷贝构造函数的概念、作用、特点、规则、默认行为以及如何自定义实现,对于编写健壮和高效的C++程序至关重要。

 C++类和对象系列文章,可点击下方链接阅读:

【C++指南】类和对象(一):类和对象的定义和使用 基础讲解_c++ 类对象的使用-CSDN博客

【C++指南】类和对象(二):类的默认成员函数——全面剖析 :构造函数-CSDN博客

【C++指南】类和对象(三):类的默认成员函数——全面剖析: 析构函数-CSDN博客

【C++指南】类和对象(四):类的默认成员函数——全面剖析 拷贝构造函数-CSDN博客

【C++指南】类和对象(五):类的默认成员函数——全面剖析 赋值运算符重载函数-CSDN博客

目录

引言

🍃概念

🍃作用

🍃特点

触发拷贝函数自动调用的情况:

🍃规则

🍃默认拷贝构造函数的行为

🍃自定义实现拷贝构造函数

🍃总结


🍃概念

如果⼀个构造函数的第⼀个参数是自身类类型的引用,且任何额外的参数都有默认值,则此构造函数 也叫做拷贝构造函数。

拷贝构造函数是一种特殊的构造函数,它接受一个同类型的对象的引用作为参数,用于初始化新创建的对象。

拷贝构造函数的声明通常如下:

ClassName(const ClassName& other);
其中,ClassName是类的名字,other 是传入的对象。 

🍃作用

拷贝构造函数的主要作用是实现对象的深拷贝或浅拷贝

  • 深拷贝:在内存中为对象分配新的空间,并复制源对象的所有成员(包括动态分配的内存)。
  • 浅拷贝:仅复制对象的成员值,如果成员包含指针,则两个对象将共享相同的内存地址。

关于浅拷贝与深拷贝的详细内容可以参考文章:

【C++指南】C++中的浅拷贝与深拷贝:深入剖析-CSDN博客 

🍃特点

  • 自动调用:在对象通过另一个对象初始化时,拷贝构造函数会被自动调用。
  • 参数传递:拷贝构造函数的参数是常量引用(const ClassName&),避免不必要的拷贝,同时防止对象在拷贝过程中被修改。

拷贝构造函数的参数必须是类类型对象的引用,而不是传值方式。主要是因为:

避免无限递归

如果拷贝构造函数的参数是传值方式,那么在调用拷贝构造函数时,编译器会尝试创建一个临时对象来传递给该函数。这个临时对象的创建又会调用拷贝构造函数,从而导致无限递归。最终,这会导致栈溢出和编译错误。

触发拷贝函数自动调用的情况:

1.对象初始化

  • 使用另一个同类型的对象来初始化一个新对象时。
MyClass obj1;  
MyClass obj2 = obj1;  // 调用拷贝构造函数

 2.函数参数传递

  • 当一个对象作为值参数传递给函数时。
void func(MyClass obj) {  // 在这里,obj是通过拷贝构造函数创建的  
}  
MyClass obj1;  
func(obj1);  // 调用拷贝构造函数

3.函数返回值

  • 当一个函数返回一个对象(作为值)时,会调用拷贝构造函数来构造返回的对象。
MyClass func() {  MyClass obj;  return obj;  // 调用拷贝构造函数  
}

4.编译器生成的临时对象

  • 编译器在某些情况下会生成临时对象,例如,在表达式中计算中间结果时。
MyClass obj = MyClass();  // 这里的`MyClass()`创建了一个临时对象,然后调用拷贝构造函数赋值给obj

🍃规则

  • 如果类中没有显式定义拷贝构造函数,编译器会提供一个默认的拷贝构造函数。
  • 拷贝构造函数不能被声明为const,因为它需要修改(初始化)目标对象。
  • 拷贝构造函数必须是可访问的,以便在需要时能够被调用。

🍃默认拷贝构造函数的行为

默认拷贝构造函数的行为是逐成员复制,对于基本类型成员,直接复制值,也就是浅拷贝对于对象成员,调用其拷贝构造函数

这种默认行为通常适用于不包含动态分配内存或资源管理(如文件句柄、网络连接等)的简单类。

🍃自定义实现拷贝构造函数

当类包含动态分配的内存、指针或需要管理的资源时,必须自定义拷贝构造函数来实现深拷贝,以避免浅拷贝带来的问题(如重复释放内存、数据不一致等)。

Tips:

如果⼀个类显式实现了析构并释放资源,那么他就 需要显式写拷贝构造,否则就不需要

以下是一个包含动态分配内存的类的示例,展示如何自定义拷贝构造函数:

#include <iostream>  
#include <cstring>  class MyClass {  
private:  char* data;  public:  // 默认构造函数  MyClass(const char* str = "") {  data = new char[strlen(str) + 1];  strcpy(data, str);  }  // 拷贝构造函数  MyClass(const MyClass& other) {  data = new char[strlen(other.data) + 1];  strcpy(data, other.data);  }  // 析构函数  ~MyClass() {  delete[] data;  }  // 打印数据  void print() const {  std::cout << data << std::endl;  }  
};  int main() {  MyClass obj1("Hello");  MyClass obj2 = obj1; // 调用拷贝构造函数  obj1.print(); // 输出: Hello  obj2.print(); // 输出: Hello  return 0;  
}
在这个例子中,MyClass 包含一个指向字符数组的指针。自定义拷贝构造函数通过分配新的内存并复制字符串内容,实现了深拷贝。析构函数负责释放动态分配的内存,防止内存泄漏。

🍃总结

  • 拷贝构造函数是C++中用于通过另一个对象初始化新对象的特殊构造函数。
  • 它接受一个同类型的常量引用作为参数。
  • 如果没有显式定义,编译器会提供一个默认的拷贝构造函数,逐成员复制对象。
  • 自定义拷贝构造函数通常用于实现深拷贝,以避免浅拷贝带来的问题。
  • 编写拷贝构造函数时,需要特别注意动态分配的内存和需要管理的资源,确保正确复制和释放。

通过理解和应用拷贝构造函数,可以编写出更加健壮和高效的C++程序。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/56195.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GitLab+Jenkins 实现 Webhook 自动化触发构建

在持续集成和持续部署&#xff08;CI/CD&#xff09;过程中&#xff0c;如何实现代码提交后自动触发构建&#xff1f;今天&#xff0c;我们将通过GitLab与Jenkins的集成&#xff0c;利用Webhook实现自动化触发构建&#xff0c;为你的开发流程注入高效能量&#xff01; 在每次代…

Java 多线程(六)—— 线程池 和 工厂模式

线程池 随着现代计算机的发展&#xff0c;任务越来越多&#xff0c;线程创建也逐渐增加&#xff0c;每次让操作系统创建线程这个开销就有点大&#xff0c;因此&#xff0c;我们诞生了线程池的概念&#xff0c;线程池里面有很多线程&#xff0c;这些线程可以被用户去调用执行任…

Java最全面试题->Java基础面试题->JavaSE面试题->异常面试题

文章目录 异常1.说一下Java中的异常体系&#xff1f;2.Error和Exception的区别3.写出你最常见的 5 个 RuntimeException&#xff1f;4.如何处理异常?5.try()里面有⼀个return语句&#xff0c; 那么后面的finally{}里面的代码会不会被执行&#xff1f;什么时候执行&#xff0c;…

C++ 进阶:类相关特性的深入探讨

⭐在对C 中类的6个默认成员函数有了初步了解之后&#xff0c;现在我们进行对类相关特性的深入探讨&#xff01; &#x1f525;&#x1f525;&#x1f525;【C】类的默认成员函数&#xff1a;深入剖析与应用&#xff08;上&#xff09; 【C】类的默认成员函数&#xff1a;深入剖…

初阶数据结构【3】--单链表(比顺序表还好的一种数据结构!!!)

本章概述 前情回顾单链表实现单链表彩蛋时刻&#xff01;&#xff01;&#xff01; 前情回顾 咱们在上一章博客点击&#xff1a;《顺序表》的末尾&#xff0c;提出了一个问题&#xff0c;讲出了顺序表的缺点——有点浪费空间。所以&#xff0c;为了解决这个问题&#xff0c;我…

TypeScript 出现过的问题

不能将类型“unknown”分配给类型“string”。 不能直接将类型“unknown”分配给类型“string” /**** 【1 - 问题】会画红波浪线 ****/ window.document.title to?.meta?.title || /**** 【2 - 解决】解决红波浪线 ****/ const title: unknown to?.meta?.title || if …

QML 基本动画

在介绍完 QML 动画框架之后,现在我们来看看具体的动画及其用法。先从最常用的基本动画入手,这些动画包括:PropertyAnimation、ColorAnimation、Vector3dAnimation 和 PathAnimation 等,它们不仅能够帮助我们轻松地为应用程序添加动态效果,还能显著提升用户体验,使得界面更…

vue3 解决背景图与窗口留有间隙的问题

需要实现一个登录界面&#xff0c;login.vue的代码如下&#xff1a; <script> import { ref } from vue;export default {setup() {return {};}, }; </script><template><div id"login-container" class"login-container"><di…

中国古代数学的杰出研究成果之一 - 杨辉三角 - 怎么用go、C++进行编程解决

杨辉三角&#xff0c;又称帕斯卡三角形&#xff08;Pascals Triangle&#xff09;&#xff0c;是组合数学中的一个重要概念。它是一个三角形数组&#xff0c;其中每个数字是它上方左上方和右上方的数字之和。杨辉三角的每一行都代表了二项式展开式的系数&#xff0c;因此在数学…

利用 OBS 推送 WEBRTC 流到 smart rtmpd

webrtc whip 推流 & whep 拉流简介 RFC 定义 通用的 webrtc 对于 SDP 协议的交换已经有对应的 RFC 草案出炉了。这就是 WHIP( push stream ) & WHEP ( pull stream ) . WHIP RFC Link: https://www.ietf.org/archive/id/draft-ietf-wish-whip-01.html WHEP RFC Link:…

ubuntu 开启haproxy UI

一、修改haproxy.cfg nano /etc/haproxy/haproxy.cfg 添加一段 listen statsbind *:8080stats enablestats uri /uistats refresh 10sstats auth admin:123456stats admin if TRUE 重启 sudo systemctl restart haproxy 浏览器访问&#xff1a; http://192.168.31.182:80…

搜维尔科技:SenseGlove触觉反馈数据手套的用途和作用

无论是VR培训、遥控机器人、研究还是营销&#xff0c;我们的VR触觉手套都能让虚拟世界更具沉浸感和吸引力。借助我们的硬件和直观的软件开发工具&#xff0c;研究人员和开发人员可以创建真正的触觉交互。 VR培训 使用 SenseGlove进行虚拟现实训练可产生与现实训练类似的效果&a…

MySQL-CRUD-基础-(详解) ┗( ▔, ▔ )┛

目录 ❄️一、新增&#xff08;Create&#xff09;&#xff1a; ☑ 1、单行数据 全列插入&#xff1a; ☑ 2、指定列插入&#xff1a; ☑ 3、多行插入&#xff1a; ❄️二、查询&#xff08;Retrieve&#xff09;&#xff1a; ☑ 1、全列查询&#xff1a; ☑ 2、指定列查询&a…

【数据结构与算法】走进数据结构的“时间胶囊”——栈

大家好&#xff0c;我是小卡皮巴拉 文章目录 目录 引言 一.栈的基本概念 1.1 定义 1.2 特性 1.3 基本操作 二.栈的实现方式 2.1 顺序栈 2.2 链栈 三.顺序栈的实现 定义顺序栈的结构 初始化 入栈 检查栈是否为空 出栈 销毁 四.链栈的实现 定义链栈的结构 初始…

新版idea菜单栏展开与合并

新版idea把菜单栏合并了看着很是不习惯&#xff0c;找了半天原来在这里展开 ① 点击文件 -> 设置 ② 点击外观与行为 -> 外观 -> 合并主菜单和窗口标题 然后确定&#xff0c;重启即可

戴维南,叠加,稳态笔记

一点点学习笔记,仅做个人复习使用 节点电压分清电流电压源&#xff0c;电流源才能写在右边&#xff0c;容易混淆 叠加定理仅适用于线性电路&#xff0c;且不能用于计算功率&#xff0c;主要是方向&#xff0c;要看源的方向判断等效之后的&#xff0c;受控源不参与除源&#x…

数据库表的创建

运用的环境是pychram python3.11.4 创建一个表需要用到以下语法 注释已经写清楚各种语法的含义&#xff0c;记住缩进是你程序运行的关键&#xff0c;因为程序是看你的缩进来判断你的运行逻辑&#xff0c;像我这个就是缩进不合理导致的报错 那么今天分享就到这里&#xff0c;谢…

android11 usb摄像头添加多分辨率支持

部分借鉴于&#xff1a;https://blog.csdn.net/weixin_45639314/article/details/142210634 目录 一、需求介绍 二、UVC介绍 三、解析 四、补丁修改 1、预览的限制主要存在于hal层和framework层 2、添加所需要的分辨率&#xff1a; 3、hal层修改 4、frameworks 5、备…

第九届清洁能源与发电技术国际学术会议(CEPGT 2024)

第九届清洁能源与发电技术国际学术会议&#xff08;CEPGT 2024&#xff09; 2024 9th International Conference on Clean Energy and Power Generation Technology (CEPGT 2024) 【早投稿早录用&#xff0c;享受早鸟优惠】 CEPGT 2024会议已上线至IEEE官网 第九届清洁能源…

15分钟学Go 第2天:安装Go环境

第2天&#xff1a;安装Go环境 1. 引言 在学习Go语言之前&#xff0c;首先需要配置好本地开发环境。本节将详细介绍如何在Windows 11上安装和配置Go语言环境&#xff0c;包括安装步骤、环境变量设置、VS Code配置与测试、以及常见问题解决方案。完成这些步骤后&#xff0c;你将…