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

news/2024/10/26 10:12:56/

 引言

拷贝构造函数是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.ppmy.cn/news/1542083.html

相关文章

Go操作Redis

在现代的软件开发中&#xff0c;Redis 已经成为了一个不可或缺的组成部分&#xff0c;它以其卓越的性能和灵活性被广泛应用于缓存、消息队列、会话存储等多种场景。Go 语言&#xff0c;以其并发能力强和运行效率高的特点&#xff0c;成为了后端开发的首选语言之一。当 Go 遇上 …

闯关leetcode——203. Remove Linked List Elements

大纲 题目地址内容 解题代码地址 题目 地址 https://leetcode.com/problems/remove-linked-list-elements/description/ 内容 Given the head of a linked list and an integer val, remove all the nodes of the linked list that has Node.val val, and return the new …

基于GA遗传优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 matlab2022a 3.部分核心程序 &#xff08;完整版代码包含详细中文注释和操作步骤视频&#xff09…

webpack解决使用window.open方法打开history路由页面提示404的问题

问题: 一般情况下应该使用history.push(/ssh)打开history路由页面 但项目中使用window.open(/ssh),然后使用new WebSocket进行通信 开发环境下启动项目后,/ssh页面打开却显示cannot get /ssh,控制台提示404 排查问题: 在React开发环境中使用 window.open 打开路由页面时&a…

论文速读:YOLO-G,用于跨域目标检测的改进YOLO(Plos One 2023)

原文标题&#xff1a;YOLO-G: Improved YOLO for cross-domain object detection 中文标题&#xff1a;YOLO-G&#xff1a;用于跨域目标检测的改进YOLO 论文地址&#xff1a; 百度网盘 请输入提取码 提取码&#xff1a;z8h7 代码地址&#xff1a; GitHub - airy975924806/yolo…

echarts 矩阵树图treemap

1、根据value值渲染各个数据的占用面积&#xff1b; 2、根据percentValue值判断各个数据的颜色展示&#xff1b; 3、根据value值判断各个数据的标签名称字号的大小&#xff08;占用面积越大字号越大&#xff0c;占用面积越小字号越小&#xff09;&#xff1b; 直接上代码&…

纯血鸿蒙的未来前景

纯血鸿蒙作为华为推出的新一代操作系统&#xff0c;其未来的发展前景可以从多个方面进行分析。 从技术角度来看&#xff0c;纯血鸿蒙实现了全面的自主可控。它去除了传统的AOSP代码&#xff0c;仅支持鸿蒙内核和鸿蒙系统的应用&#xff0c;不再兼容安卓OS。这种技术上的独立性…

使用单链表实现集合操作:并集、交集与差集

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…