什么是 C++ 中的友元函数和友元类?友元的作用是什么?有什么注意事项?

友元函数(Friend Function)

定义

友元函数是在类定义中用关键字friend声明的非成员函数。它可以访问类的私有(private)和保护(protected)成员。

作用和使用场景

友元函数主要用于在某些情况下,需要在类的外部函数中访问类的私有或保护成员。例如,在操作符重载中,当需要访问类的私有数据成员来实现特定的操作符功能时,友元函数就很有用。

示例

假设有一个Complex类,表示复数,包含实部real和虚部imaginary两个私有成员变量。我们想实现一个函数来计算两个复数的加法并返回结果。

class Complex {
private:double real;double imaginary;
public:Complex(double r = 0, double i = 0) : real(r), imaginary(i) {}friend Complex addComplex(const Complex& c1, const Complex& c2);
};
Complex addComplex(const Complex& c1, const Complex& c2) {Complex result;result.real = c1.real + c2.real;result.imaginary = c1.imaginary + c2.imaginary;return result;
}

在这个例子中,addComplex函数是Complex类的友元函数。它可以直接访问Complex类的私有成员real和imaginary,从而实现两个复数的加法运算。

友元类(Friend Class)

定义

友元类是在一个类中用friend关键字声明的另一个类。友元类的所有成员函数都可以访问声明它为友元的类的私有和保护成员。

作用和使用场景

当两个类之间存在紧密的合作关系,需要一个类能够访问另一个类的私有和保护成员来完成特定的功能时,就可以使用友元类。比如,在一个图形绘制系统中,有一个Shape类和一个Renderer类,Renderer类需要访问Shape类的私有成员来正确地绘制形状,此时可以将Renderer类声明为Shape类的友元类。

示例

假设有一个Car类和一个Mechanic类。Mechanic类需要访问Car类的私有成员来进行维修等操作。

class Car {
private:int engineStatus;
public:Car(int status = 0) : engineStatus(status) {}friend class Mechanic;
};
class Mechanic {
public:void repairEngine(Car& c) {c.engineStatus = 1;  // 可以访问Car类的私有成员engineStatus}
};

在这个例子中,Mechanic类是Car类的友元类,Mechanic类中的repairEngine函数可以访问Car类的私有成员engineStatus来修改汽车发动机的状态。

好处:可以通过友元在类外访问类内的私有 和 受保护类型的成员

坏处:破坏了类的封装性

友元的作用

增强灵活性

访问私有成员:在 C++ 中,类的私有成员(private)和保护成员(protected)通常不能被外部函数或其他类访问。友元函数和友元类提供了一种机制,使得外部函数或其他类能够访问这些受限的成员。例如,在实现某些操作符重载函数时,可能需要访问类的私有数据成员来正确地实现操作符的功能。

协同工作:在一些复杂的程序设计场景中,不同的类可能需要紧密协作。比如,一个图形绘制系统中有图形类(如Circle、Rectangle)和绘制工具类(如DrawingTool)。绘图工具类需要访问图形类的内部细节(如圆心坐标、边长等私有数据)来进行精确的绘制,通过将DrawingTool类声明为图形类的友元类,可以方便地实现这种协作。

方便代码实现

提高效率:在某些情况下,使用友元可以避免通过公有接口函数访问私有成员所带来的额外开销。例如,若频繁地通过公有函数获取和设置私有数据成员的值,会涉及函数调用的开销。而友元函数直接访问私有成员,可以减少这种开销,在性能敏感的代码部分可能会很有用。

操作符重载:对于一些自定义类型的操作符重载,友元函数提供了一种自然的方式。例如,对于复数类Complex,要实现+操作符重载来相加两个复数。使用友元函数可以方便地访问两个操作数(复数对象)的私有成员(实部和虚部),使得操作符重载的实现更加简洁直观。

注意事项

破坏封装性

友元机制打破了类的封装原则。类的封装性使得数据隐藏在类内部,只能通过公有接口访问,这有助于保证数据的完整性和安全性。而友元函数和友元类可以直接访问私有和保护成员,这可能会导致代码的可维护性降低。如果滥用友元,可能会使代码变得难以理解和调试,因为外部函数或类对类内部数据的访问不受常规封装规则的限制。

谨慎使用

应该谨慎地决定哪些函数或类需要成为友元。只有在确实有必要访问另一个类的私有或保护成员,并且这种访问是合理的、有助于程序设计的情况下,才应该使用友元。例如,不要仅仅为了方便而随意将大量外部函数或类声明为友元,而应该先考虑是否可以通过改进类的公有接口来满足需求。

双向友元关系的复杂性

当两个类相互声明为友元时(即 A 类是 B 类的友元,同时 B 类也是 A 类的友元),可能会导致复杂的依赖关系。这种双向友元关系可能会使代码的逻辑变得复杂,在修改其中一个类的内部实现时,可能会影响到另一个类。因此,在使用双向友元时,需要特别小心,充分考虑可能产生的后果。

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

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

相关文章

擎耀数字车灯CAN/LIN总线网络定向数据采集控制解决方案实施流程

2024年是数字车灯崛起的元年,随着车辆的智能化和网络化程度不断提高,车载网络系统(如CAN总线)成为连接各个电子控制单元(ECU)的重要纽带。车灯作为车辆重要的安全组件之一,其工作状态直接影响到…

【C++之STL】摸清 string 的模拟实现(上)

文章目录 1. 为什么要模拟实现?2. 基本框架搭建3. 构造函数3. 1 默认构造/from c_str3. 2 拷贝构造3. 2. 1 深浅拷贝 3. 3 fill3. 4 迭代器区间构造 4. 容量操作4. 1 size()和capacity()和empty()4. 2 clear()4. 3 resize()4. 4 reserve() 1. 为什么要模拟实现&…

视频直播5G CPE解决方案:ZX7981PG/ZX7981PMWIFI6网络覆盖

方案背景 视频直播蓬勃发展的当下,传统直播网络联网方式的局限性越来越明显。目前传统直播的局限性主要集中在以下几个方面: 传统直播间网络架构条件有限,可连接WIFI数量少,多终端同时直播难以维持;目前4G网络带宽有限…

input file结合vue3和vant实现上传图片效果,并显示上传进度百分比%

这里写自定义目录标题 采用的dom结构是input file,label事件绑定,一下为代码传入参数为uploadNum实现效果如图上传中,图片1上传成功,图片2 采用的dom结构是input file,label事件绑定,一下为代码 传入参数为…

SELECT 语句详解

开发准备 注:如果你是从上一节直接进入本节进行学习的,请先删除上一节建立的数据库mysql_shiyan,删除语句为DROP DATABASE mysql_shiyan;。在正式开始本实验内容之前,需要先下载相关数据库表,搭建好一个名为mysql_shiyan 的数据库(有三张表:department,employee,projec…

重力传感器算法概述!

一、核心技术 高精度重力测量技术: 无人机重力传感器的核心技术之一是能够高精度地测量重力加速度数据。这通常依赖于先进的传感器设计和制造工艺,以确保传感器具有高度的灵敏度和稳定性。 例如,中国船舶第七〇七研究所自主研发的低空重力…

炼码LintCode--数据库题库(级别:中等;数量:更新中~)--刷题笔记_03

目录 炼码LintCode--数据库题库(级别:中等;数量:更新中~)--刷题笔记_033617 更换连续两个人的座位(case when)题:sql:解释: 3615 数据中位数(窗…

【stm入门学习SPI_铁头山羊系列教程】

stm入门学习SPI_铁头山羊教程 1.SPI总线1.电路结构与通信协议2.SPI的特点:3. 极性 相位4. 4中时钟模式5. 比特位的传输模式6.数据宽度 2. SPI引脚IO引脚初始化 1.SPI总线 1.电路结构与通信协议 主机向从机NSS引脚发送低电压,选中该从机。 主机通过向MOS…

RK3568平台开发系列讲解(platform虚拟总线驱动篇)实验:点亮一个LED

🚀返回专栏总目录 文章目录 一、设备树二、平台驱动三、应用沉淀、分享、成长,让自己和他人都能有所收获!😄 📢xxx 程序编写的主要内容为添加 LED 灯的设备树节点、在驱动程序中使用 of 函数获取设备节点中的属性,编写测试应用程序。 • 首先向设备树添加 LED 设备节点…

Spring Boot 与腾讯云 MySQL 监听 Binlog 数据变化,并使用 UI 展示页面效果

引言 在现代的分布式系统和微服务架构中,数据同步和变更监控是保证系统一致性和实时性的核心问题之一。MySQL 数据库的 binlog(二进制日志)功能能够记录所有对数据库的修改操作,如插入(INSERT)、更新&…

菜鸟驿站二维码/一维码 取件识别功能

特别注意需要引入 库文 ZXing 可跳转: 记录【WinForm】C#学习使用ZXing.Net生成条码过程_c# zxing-CSDN博客 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using static System.Net.…

PlantUML——时序图

PlantUML时序图 背景 时序图(Sequence Diagram),又名序列图、循序图,是一种UML交互图,用于描述对象之间发送消息的时间顺序,显示多个对象之间的动态协作。时序图的使用场景非常广泛,几乎各行各…

算法——链表相交(leetcode23)

链表相交这题就是找出两个相交链表相交的节点并返回 如上图假设上方第一个节点是链表A的头结点下方第一个节点是链表B的头结点 解法有以下两种 方法一(移动长链表指针后同步移动两个链表的指针直至相等) 也就是先遍历链表A和链表B的长度接着得到链表A和B长度的差值然后领长链…

STM32单片机锁死

自己画了一块stm32f407板子,外部晶振用了25MHz,烧写了8MHz的程序,第一次烧写成功,第二次开始识别不到芯片,第一次烧写成功由于外部晶振为25Hz,芯片内频率计算器却是按照8MHz写的,所以得出最后的…

Windows文件资源管理器增强工具

引言: 资源管理器在我们使用电脑时是经常用到的,各种文件资源等的分类整理都离不开它。但是Windows Explorer确实不好用,不智能,不符合人体工程学。特别是在一些场合,在打开的一堆文件夹里,想从中找到自己要…

聚类中3个解空间的描述

深度学习中做分类任务时,我们常常根据最后的全连接层得到一组向量A(比如:[0.9, 0.7, 0.2]),这组向量经过归一化得到向量B(比如:[0.5, 0.3, 0.2]),再根据B向量采用概率最大…

Empirical analysis of hardware-assisted GPU virtualization

​ 年份:2019 作者:Anshuj Garg 会议:ESCI 出版商:IEEE 摘要 本篇文章对vGPU虚拟化的性能开销、调度算法的影响、同构与异构工作负载的干扰效应,以及PCI直通与vGPU的性能差异进行了研究。结果表明,vGP…

Java面试题2024-Java基础

Java基础 1、 Java语言有哪些特点 1、简单易学、有丰富的类库 2、面向对象(Java最重要的特性,让程序耦合度更低,内聚性更高) 3、与平台无关性(JVM是Java跨平台使用的根本) 4、可靠安全 5、支持多线程 2、…

【案例分享】运用 Infragistics Ultimate UI 让工业物联网 IIoT 数据流更易于访问

客户概况 贝克休斯旗下的 Bently Nevada 是状态监测和资产保护领域的全球领导者。该公司拥有 60 多年的专业知识,在全球安装了超过 600 万个传感器和 100,000 个机架监测系统。 如今,Bently Nevada的开发团队正在使用现代 UI 工具包来增强他们的系统&a…

PHM技术:基于支持向量机的智能故障诊断 | 行星齿轮箱智能故障诊断

目录 1.数据获取 2.特征提取与选择 3.健康状态识别 1.数据获取 用的行星齿轮箱数据采集自图1中的多级齿轮传动系统实验台中,在实验过程中,分别模拟了8种行星齿轮箱的健康状态,包括正常、第一级太阳轮点蚀、第一级太阳轮齿根裂纹、第一级…