c++--拷贝构造函数友元函数

目录

1.拷贝构造函数是什么

2.拷贝构造函数的基本格式

2.1 默认拷贝构造函数(浅拷贝)

2.2 深拷贝(Deep Copy)

2.3 浅拷贝(Shallow Copy)

2.3 浅拷贝和深拷贝总结

2.友元函数


1.拷贝构造函数是什么

拷贝构造函数是一个特殊的构造函数,用于在创建新对象时,用已有对象的数据来初始化新对象。拷贝构造函数的典型应用场景包括:

  1. 传值参数:当一个对象通过值传递给函数时,编译器会调用拷贝构造函数来创建函数参数的副本。
  • 为了将 obj1 传递给 passByValue,C++ 会调用 拷贝构造函数 创建一个新的 MyClass 对象。这个新的对象会有自己的 str,内容是 obj1.str
  • passByValue 函数内部,调用 obj.display() 显示副本对象的数据。
  • 注意:obj 是一个副本,函数执行完后,它会被销毁,所做的任何更改都不会影响 obj1
  1. 返回值:当函数返回一个对象时,编译器会用返回的对象来创建一个临时副本,然后将该副本返回给调用者。
  • returnByValue 函数中,创建了一个局部对象 temp,它的 str 初始化为 "临时对象"
  • 然后函数通过 return temp;temp 返回给调用者。
  • 返回时,C++ 会调用 拷贝构造函数 来创建一个新的对象,这个新对象的内容就是 temp 对象的副本。这里的拷贝构造函数会执行字符串的复制操作,确保新对象拥有自己的 str 数据。
  1. 对象初始化:创建新对象并将另一个对象赋值给它时,例如 MyClass obj2 = obj1;
#include <iostream>
#include <cstring>class MyClass {char* str;public:// 普通构造函数MyClass(const char* s) {str = new char[strlen(s) + 1];strcpy(str, s);std::cout << "调用普通构造函数" << std::endl;}// 拷贝构造函数MyClass(const MyClass &obj) {str = new char[strlen(obj.str) + 1];strcpy(str, obj.str);std::cout << "调用拷贝构造函数" << std::endl;}// 显示字符串void display() const {std::cout << "字符串内容: " << str << std::endl;}// 析构函数~MyClass() {delete[] str;}
};// 示例 1:传值参数
void passByValue(MyClass obj) {obj.display();
}// 示例 2:返回值
MyClass returnByValue() {MyClass temp("临时对象");return temp;
}int main() {// 示例 3:对象初始化MyClass obj1("Hello");  // 调用普通构造函数MyClass obj2 = obj1;    // 调用拷贝构造函数 (对象初始化)// 示例 1:传值参数passByValue(obj1);  // 调用拷贝构造函数 (传值参数)// 示例 2:返回值MyClass obj3 = returnByValue();  // 调用拷贝构造函数 (返回值)obj1.display();obj2.display();obj3.display();return 0;
}

2.拷贝构造函数的基本格式

拷贝构造函数的格式如下:

ClassName(const ClassName &other);

这里的参数 other 是对同类型对象的常量引用

使用引用的原因是避免在传参时调用拷贝构造函数,导致递归调用;而使用常量引用可以避免修改原对象。

如果other 是传值传递的,也就是说,编译器需要创建 other 的副本。而为了创建这个副本,编译器会再次调用拷贝构造函数——这样就会导致递归调用,拷贝构造函数会一遍一遍地自己调用自己,最终导致栈溢出错误

2.1 默认拷贝构造函数(浅拷贝)

如果没有定义拷贝构造函数,编译器会生成一个默认拷贝构造函数,对每个数据成员进行浅拷贝浅拷贝的方式是逐个复制数据成员,即将源对象的每个成员变量直接赋值给新对象。

浅拷贝对包含指针的类可能不适用。如果类中包含动态分配的资源(例如 new 分配的内存),浅拷贝会导致新旧对象指向相同的内存,可能导致一些问题:

  • 双重释放:如果两个对象指向同一块内存,当一个对象析构时会释放这块内存,而当另一个对象析构时会再次尝试释放这块内存,从而引发错误。
  • 数据混乱:如果一个对象修改了内存的内容,那么另一个对象也会受影响,因为它们共享同一块内存。

为了避免这些问题,通常需要自定义拷贝构造函数

2.2 深拷贝(Deep Copy)

深拷贝会创建一个新内存区域,并复制实际的数据到新内存,这样两个对象互不影响。深拷贝适用于包含指针成员的类。

#include <iostream>
#include <cstring>class DeepCopyClass {
public:char* data;// 构造函数DeepCopyClass(const char* str) {data = new char[strlen(str) + 1];strcpy(data, str);}// 深拷贝构造函数DeepCopyClass(const DeepCopyClass &obj) {data = new char[strlen(obj.data) + 1];strcpy(data, obj.data); // 复制实际内容}~DeepCopyClass() {delete[] data;}
};int main() {DeepCopyClass obj1("Hello");DeepCopyClass obj2 = obj1; // 调用深拷贝构造函数// 修改 obj2 的数据strcpy(obj2.data, "World");std::cout << "obj1 数据: " << obj1.data << std::endl; // 输出 "Hello",因为两者独立std::cout << "obj2 数据: " << obj2.data << std::endl;return 0;
}

2.3 浅拷贝(Shallow Copy)

浅拷贝仅复制对象的非动态内存内容或指针的地址。这意味着:

  • 浅拷贝会将指针地址复制到新对象中,但不会创建新内存。新对象的指针与原对象指向相同的内存区域。
  • 如果两个对象共享同一内存区域时,一个对象的修改会影响另一个对象。
  • 当程序试图释放内存时,会因为多次释放相同的内存而导致悬挂指针内存泄漏问题。
#include <iostream>
#include <cstring>class ShallowCopyClass {
public:char* data;// 构造函数ShallowCopyClass(const char* str) {data = new char[strlen(str) + 1];strcpy(data, str);}// 浅拷贝构造函数ShallowCopyClass(const ShallowCopyClass &obj) {data = obj.data; // 仅复制指针地址(浅拷贝)}~ShallowCopyClass() {delete[] data;}
};int main() {ShallowCopyClass obj1("Hello");ShallowCopyClass obj2 = obj1; // 调用浅拷贝构造函数// 修改 obj2 的数据strcpy(obj2.data, "World");std::cout << "obj1 数据: " << obj1.data << std::endl; // 输出 "World",因为两者共享相同内存std::cout << "obj2 数据: " << obj2.data << std::endl;return 0;
}

2.3 浅拷贝和深拷贝总结

特性浅拷贝深拷贝
内存分配复制指针地址,指向同一内存分配新内存,复制数据
内存管理共用同一内存,容易出现问题各自独立,互不影响
适用场景不涉及动态内存分配的简单对象含指针成员的复杂对象
示例复制地址,仅共享数据复制内容,独立内存

2.友元函数

友元函数(Friend Function)是一种特殊的函数,可以访问类的私有(private)和保护(protected)成员,即使它不是该类的成员函数。通常,在面向对象编程中,类的私有和保护成员只能被该类的成员函数或子类访问,而友元函数则打破了这个限制,允许非成员函数访问类的私有和保护成员。

友元函数的定义方式是在类内部使用关键字 friend 声明该函数

  #include <iostream>
using namespace std;class Box {
private:int width;public:Box() : width(0) {}// 将 friend 关键字用于函数声明,使其成为友元函数friend void setWidth(Box &box, int w);
};// 友元函数定义
void setWidth(Box &box, int w) {// 可以直接访问 Box 类的私有成员 widthbox.width = w;
}int main() {Box box;setWidth(box, 10);  // 调用友元函数return 0;
}

setWidthBox 类的友元函数,虽然它不是 Box 类的成员函数,但可以直接访问 Box 类的私有成员 width

通过友元函数,可以实现:访问私有和保护成员:在特定情况下,让非成员函数或其他类可以访问类的私有和保护成员。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

python怎么去掉换行符

换行符与其他字符并没有区别&#xff0c;由于换行符总是最后一个字符&#xff0c;所以直接选择除去最后一个字符的所有字符即可。 x abc\n x[:-1] 也可以使用字符串的strip()方法 但是strip()方法除了会去掉换行符&#xff0c;还会去掉空格等其他字符。 x.strip()

Webserver(4.4)多进程/多线程实现并发服务器

目录 多进程实现并发服务器多线程实现并发服务器TCP状态转换 多进程实现并发服务器 要实现TCP服务器处理并发的任务&#xff0c;使用多线程或者多进程来解决 一个父进程&#xff0c;多个子进程 父进程负责等待并接受客户端的连接 子进程&#xff1a;完成通信&#xff0c;接收一…

Pinterest会成为亚马逊的新流量入口吗?

Pinterest 作为一个以图片分享为主的社交媒体平台&#xff0c;全球月活跃用户约为 4.368亿。同时&#xff0c;Pinterest 的用户群体以女性为主&#xff0c;占比高达 70% 以上&#xff0c;且多数是 18 岁到 44 岁之间的中高收入人群&#xff0c;具有较强的购买力和消费能力。对于…

SpeechT5 模型

微软开源的 SpeechT5 语音模型&#xff0c;主要包括以下功能 语音转文字&#xff1a;用于自动语音识别&#xff08;ASR&#xff09;。文字转语音&#xff1a;用于合成音频&#xff08;TTS&#xff09;。语音转语音&#xff1a;用于不同声音之间的转换或进行语音增强。 T5 网络…

.NET 8 中 Entity Framework Core 的使用

本文代码&#xff1a;https://download.csdn.net/download/hefeng_aspnet/89935738 概述 Entity Framework Core (EF Core) 已成为 .NET 开发中数据访问的基石工具&#xff0c;为开发人员提供了强大而多功能的解决方案。随着 .NET 8 和 C# 10 中引入的改进&#xff0c;开发人…

我要精通前端-块级元素和行内元素再度深入学习笔记

真的发现前端天天增删改查&#xff0c;真的是问一些比较细节的知识&#xff0c;我真的懂么 1、块级元素间的margin会重叠&#xff0c; <div class"head"></div> <div class"content"></div>.head {margin: 5px;border: 10px sol…

sparkSQL的UDF,最常用的regeister方式自定义函数和udf注册方式定义UDF函数 (详细讲解)

- UDF&#xff1a;一对一的函数【User Defined Functions】 - substr、split、concat、instr、length、from_unixtime - UDAF&#xff1a;多对一的函数【User Defined Aggregation Functions】 聚合函数 - count、sum、max、min、avg、collect_set/list - UDTF&#xff1a;…

[SAP ABAP] 面向对象程序设计-类和对象

面向对象开发的特点&#xff1a;封装、继承和多态 什么是类和对象&#xff1f; 类(CLASS)是创建对象的模板&#xff0c;对象(OBJECT)是类的实例 一个类可以创建多个对象 类 > 类型 对象 > 个体 在ABAP语言中&#xff0c;定义一个类&#xff0c;需要包含定义(defin…

需求不明确时如何设计测试用例?

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 1、与产品澄清问题 需求不明确时&#xff0c;首先&#xff0c;应弄明白&#xff0c;需求有哪些模块及功能算法不明确&#xff1f; 需求有问题找相关负责人沟通…

C++:多态中的虚/纯虚函数,抽象类以及虚函数表

我们在平时&#xff0c;旅游或者是坐高铁或火车的时候。对学生票&#xff0c;军人票&#xff0c;普通票这些概念多少都有些许耳闻。而我们上篇文章也介绍过了继承与多继承。如果这些票我们都分别的去写一个类&#xff0c;当然很冗余&#xff0c;这里我们便可以去使用继承&#…

Sun Solaris开机自启配置

Sun Solaris 开机自启配置 1. 运行级别定义&#xff08;rc0.d — rcS.d&#xff09; Linux/Solaris系统启动相关目录、脚本说明&#xff1a; init: 系统启动超级进程inittab: 进程启动配置init.d: 启动脚本存放目录rc0---rc6: 运行级别目录rcS: 单用户模式启动脚本 Linux/S…

机器学习—例子:图像识别

在上篇文章中&#xff0c;在一个需求预测示例中看到了神经网络是如何工作的&#xff0c;那么如何将类似类型的想法应用于计算机视觉应用程序。 如果你正在开发人脸识别应用程序&#xff0c;让我们深入研究一下。假设一个神经网络将这样的图片作为输入&#xff0c;并输出图片中…

微服务系列五:避免雪崩问题的限流、隔离、熔断措施

目录 实验环境说明 前言 一、一片小雪花引起的雪崩&#xff01; 1.1 雪崩问题&#xff08;级联失败问题&#xff09;示意图 1.2 雪崩问题的产生原因与解决策略 二、雪崩问题的具体解决策略 2.1 请求限流 2.2 线程隔离 2.3 服务熔断 2.4 总结——具体解决策略 三、微…

C语言之写一个修改数组内容的函数

问题代码: 函数ltrim是为了消除buf字符数组中左边空格&#xff0c; memmove函数介绍 如果对c语言指针运用非常熟练的人,结合函数功能就会发现这个代码非常的傻逼&#xff0c;你会发现为什么需要返回&#xff0c;buf不用接收返回值&#xff0c;执行这个函数后buf中的内容就已经…

第二十七章 Vue异步更新之$nextTick

目录 一、概述 二、完整代码 2.1. main.js 2.2. App.vue 一、概述 需求&#xff1a;编辑标题, 弹出显示编辑框自动聚焦 1. 点击编辑&#xff0c;显示编辑框 2. 让编辑框&#xff0c;立刻获取焦点 我们常规的思路可能会编写如下代码来实现&#xff1a; 问题&#xff1a…

【含文档】基于ssm+jsp的IT论坛系统(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: apache tomcat 主要技术: Java,Spring,SpringMvc,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定义了三个…

【运维心得】按任何键都不能进BIOS三步解决

目录 第一步 键盘 第二步 工具 第三步 短路 估计经常搞运维的朋友&#xff0c;会经常碰到这个问题。 第一步 键盘 这个现象出现&#xff0c;首先要确定开机时&#xff0c;屏幕上是否会显示提示字符&#xff1f;比如F2、F10、DEL键之类的&#xff0c;如果有&#xff0c;那么就…

OpenCV基础05_GUI和PyMsql

目录 一、PySimpleGUI 1、布局和窗口 2、文本框组件 3、视频处理 4、图片处理 二、pymsql 1、数据库操作 2、数据采集 3、人脸识别 一、PySimpleGUI PySimpleGUI 是一个用于简化 GUI 编程的 Python 包&#xff0c;它封装了多种底层 GUI 框架&#xff08;如 tkinter、…

动态代理IP的应用场景有哪些?

在数字化时代&#xff0c;数据的价值不言而喻&#xff0c;而动态代理IP则如同企业数据采集的隐形翅膀&#xff0c;助力企业在信息海洋中翱翔。本文将深入探讨动态代理IP的应用场景&#xff0c;揭示其如何帮助企业提升业务成功率&#xff0c;保障数据采集的安全性与稳定性。 动…

从实验室到晶圆厂:光刻胶剥离液的关键转变

根据QYResearch调研团队最新发布的《全球光刻胶剥离液市场报告2023-2029》显示&#xff0c;预计到2029年&#xff0c;全球光刻胶剥离液市场规模将攀升至15.8亿美元&#xff0c;未来几年将以8.9%的复合年增长率&#xff08;CAGR&#xff09;持续增长。 上述图表及数据均来源于QY…