C++学习笔记-友元函数的定义与使用
一、引言
在C++中,友元函数(Friend Function)是一个独特而强大的特性,它打破了类的封装性,允许一个或多个非成员函数访问类的私有(private)和保护(protected)成员。尽管这种特性在某些情况下可能引发争议,因为它违反了面向对象编程中的封装原则,但在需要高效访问类内部状态或实现某些特定设计时,友元函数却又非常适用。
1.1 封装与友元函数的关系
在面向对象编程(OOP)中,封装是一种将数据(属性)与操作这些数据的函数(方法)绑定在一起的方法。封装的主要目的是隐藏类的内部实现细节,只对外提供有限的接口供外部使用。然而,在某些情况下,我们可能希望允许某些特定的非成员函数访问类的私有成员。这时,友元函数就显得尤为重要了。
1.2 友元函数的概念
友元函数不是类的成员函数,但它可以访问类的所有私有(private)和保护(protected)成员。要使一个函数成为类的友元,需要在类定义中声明该函数为友元。友元函数可以是普通函数,也可以是其他类的成员函数。
二、友元函数的定义与使用
2.1 定义友元函数
在类定义中,使用friend关键字可以声明一个或多个友元函数。友元函数的声明可以放在类的任何位置(但通常放在类定义的开始部分),但它们的定义(实现)必须在类定义之外进行。
示例:
#include <iostream> class MyClass {
private: int value; public: MyClass(int val) : value(val) {} // 声明友元函数 friend void printValue(const MyClass& obj);
}; // 定义友元函数
void printValue(const MyClass& obj) { std::cout << "Value: " << obj.value << std::endl;
} int main() { MyClass myObj(10); printValue(myObj); // 输出: Value: 10 return 0;
}
在上面的示例中,printValue函数被声明为MyClass的友元函数,因此它可以访问MyClass对象的私有成员value。
2.2 友元函数的特性
非成员函数:友元函数不是类的成员函数,因此它不会隐式地接收类的this指针。
访问权限:友元函数可以访问类的所有成员,包括私有和保护成员。
作用域:友元函数的作用域不是类的作用域,而是定义它的作用域。但是,它可以通过类的对象来访问类的成员。
数量不限:一个类可以有任意数量的友元函数。
不继承:友元关系不是继承的。如果类B是类A的友元,那么类B的子类不会自动成为类A的友元。
2.3 友元成员函数
除了普通函数外,类的成员函数也可以被声明为其他类的友元函数。这允许一个类的成员函数访问另一个类的私有成员。
示例:
#include <iostream> class MyClassB; // 前向声明 class MyClassA {
private: int value; public: MyClassA(int val) : value(val) {} // 声明MyClassB的成员函数为友元 friend void MyClassB::printValue(const MyClassA& obj);
}; class MyClassB {
public: void printValue(const MyClassA& obj) { std::cout << "Value from MyClassA: " << obj.value << std::endl; }
}; int main() { MyClassA myObjA(20); MyClassB myObjB; myObjB.printValue(myObjA); // 输出: Value from MyClassA: 20 return 0;
}
注意,在声明友元成员函数时,需要先对目标类进行前向声明,因为编译器在解析MyClassA的类定义时需要知道MyClassB是一个类名。
三、友元函数的使用场景
3.1. 重载操作符
友元函数最常见的用途之一是用于重载操作符,特别是当操作符需要访问类的私有或保护成员时。例如,在自定义的复数类(Complex)中,你可能想要重载<<操作符以便能够直接将复数对象输出到流中。由于输出操作需要访问复数对象的实部和虚部(这些通常是私有成员),因此将<<操作符定义为复数类的友元函数是一个很好的选择。
3.2. 辅助函数
有时,我们可能需要一些辅助函数来帮助实现类的功能,但这些函数并不适合作为类的成员函数。例如,如果有一个表示二维图形的类(如圆形或矩形),我们可能需要一个函数来计算两个图形是否相交。这样的函数可能需要访问图形的私有成员(如中心坐标和半径或边界),但将这些功能作为类的成员函数可能并不合适,因为它们并不是图形对象本身的操作。这时,可以将这些辅助函数声明为类的友元函数。
3.3. 模板类中的友元
在模板类中,友元函数的使用变得更加复杂但也更加有用。模板类的友元可以是另一个模板类或非模板类,甚至可以是模板函数。这允许模板类与非模板代码或不同类型的模板代码之间进行更紧密的交互。例如,你可能有一个模板容器类,并希望提供一个模板化的友元函数来执行某种类型的算法,这个算法需要访问容器的内部数据结构。
3.4. 访问控制绕过
虽然这通常不是推荐的做法,但在某些特殊情况下,友元函数可以用来绕过类的访问控制,以提供对私有成员的访问。这可以在需要优化性能(如避免通过公共接口访问时产生的额外开销)或实现特定设计模式(如访问者模式)时非常有用。然而,过度使用友元可能会破坏封装性,使代码更难理解和维护。
3.5. 跨类访问
友元函数还可以用于实现跨类访问,即一个类的友元函数可以访问另一个类的私有成员。这在设计需要紧密协作的类时特别有用,例如,在某些设计模式(如代理模式或装饰器模式)中,一个类的行为可能依赖于另一个类的内部状态。
相关文章:
C++学习笔记-友元函数的定义与使用
一、引言 在C中,友元函数(Friend Function)是一个独特而强大的特性,它打破了类的封装性,允许一个或多个非成员函数访问类的私有(private)和保护(protected)成员。尽管这…...

熵、交叉熵、KL散度
这里写目录标题 熵KL散度引入交叉熵。交叉熵的二分类公式: 再次理解SoftMax函数结束 熵 熵,是一个物理上的概念,表示一个系统的不确定性程度,或者表示一个系统的混乱程序。 下边是信息熵的演示: 信息熵的公式如下&…...

THS配置keepalive(yjm)
启动完THS管理控制台和THS后,登录控制台,进入实例管理》节点管理,可以分别使用界面配置和编辑配置设置长连接。 1、界面配置 点击界面配置》集群设置,启用长连接,设置长连接数、最大请求数和超时时间。 2、编辑配置 …...
新加坡裸机云多IP服务器特性
新加坡裸机云多IP服务器是一种高性能、稳定性强,且具备多IP地址特性的服务器。它主要适用于需要高度计算性能、网络连接稳定和高安全性的业务场景,如跨境外贸等。下面将详细探讨该类型服务器的特性,rak部落为您整理发布新加坡裸机云多IP服务器…...

深入理解ADB:Android调试桥详解与使用指南
🍎个人博客:个人主页 🏆个人专栏:Android ⛳️ 功不唐捐,玉汝于成 目录 前言 正文 1. 什么是ADB? ADB的基本原理: 2. ADB的安装与配置 安装ADB工具集: 配置ADB环境变量&am…...

PACS-医学影像信息管理系统,全影像科室PACS源码,内置包括MPR、CMPR、VR等三维处理功能
PACS系统可以覆盖医院现有放射、CT、MR、核医学、超声、内镜、病理、心电等绝大部分DICOM和非DICOM检查设备,支持从科室级、全院机、集团医院级乃至到区域PACS的平滑扩展,能够与医院HIS、集成平台的有效集成和融合,帮助医院实现了全院医学影像…...

无人机搭载无人机反制设备可行性分析
一、引言 随着无人机技术的飞速发展,无人机在各个领域的应用越来越广泛。然而,无人机的不当使用也可能带来安全隐患和隐私问题。因此,无人机反制设备应运而生,用于对非法或危险无人机进行干扰和控制。本文将对无人机搭载无人机反…...

MATLAB绘制方波、锯齿波、三角波、正弦波和余弦波、
一、引言 MATLAB是一种具有很强的数值计算和数据可视化软件,提供了许多内置函数来简化数学运算和图形的快速生成。在MATLAB中,你可以使用多种方法来快速绘制正弦波、方波和三角波。以下是一些基本的示例,展示了如何使用MATLAB的命令来实现正弦…...

【通信协议-RTCM】MSM语句(2) - RINEXMSM7语句总结(重要!自动化开发计算卫星状态常用)
注释: 在工作中主要负责的是RTCM-MSM7语句相关开发工作,所以主要介绍的就是MSM7语句相关内容 1. 相位校准参考信号 2. MSM1、MSM2、MSM3、MSM4、MSM5、MSM6和MSM7的消息头内容 DATA FIELDDF NUMBERDATA TYPENO. OF BITSNOTES Message Number - 消息编…...
ios CCUIFont.m
// // CCUIFont.h // CCFC // //#import <Foundation/Foundation.h>// 创建字体对象 #define CREATE_FONT(fontSize) [UIFont systemFontOfSize:(fontSize)]interface UIFont(cc) (void)logAllFonts;end // // CCUIFont.m // CCFC // //#import "CCUIFont.h&…...

调度子系统在特定时间执行
时序逻辑调度器设计模式允许您安排Simulink子系统在指定时间执行。以下模型说明了这种设计模式。 时序逻辑调度器图表包含以下逻辑: 时序逻辑调度器的关键行为 时序逻辑调度器图表包含两个状态,它们以不同的速率调度函数调用子系统A1、A2和A3的执行&…...

【QAC】Dashboard服务端如何配置
【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 解决Dashboard服务端如何配置的问题。 2、 问题场景 客户想使用Dashboard,Dashboard服务端如何配置。 3、软硬件环境 1、软件版本:HelixQAC23.04 2、机器环境:Windows 64bit 3…...

深入理解Linux网络(四):TCP接收阻塞
TCP socket 接收函数 recv 发出 recvfrom 系统调用。 进⼊系统调⽤后,⽤户进程就进⼊到了内核态,通过执⾏⼀系列的内核协议层函数,然后到 socket 对象的接收队列中查看是否有数据,没有的话就把⾃⼰添加到 socket 对应的等待队列⾥…...

【iOS】内存五大分区
目录 堆(Heap)是什么五大分区栈区堆区全局/静态区常量区(即.rodata)代码区(.text) 函数栈堆和栈的区别和联系图解 OC语言是C语言的超集,所以先了解C语言的内存模型的内存管理会有很大帮助。C语言…...
Jupyter Notebook: 是一个强大的交互式计算
文章目录 引言Jupyter Notebook的原理基础使用安装与启动单元格(Cell)操作快捷键 高级使用魔术命令Markdown支持可视化版本控制 优缺点优点缺点 官网链接结论 引言 Jupyter Notebook是一个强大的交互式计算环境,特别适用于数据科学、机器学习…...
【C#学习笔记】变量、变量类型
在C#中,变量是存储数据的容器,每个变量都有其特定的数据类型,这决定了变量可以存储的数据类型和大小。以下是关于C#中变量的由浅入深的详细解释,并附带代码示例和解释: 基础概念 定义: 变量是存储数据的容…...
题解:T480718 eating
eating 题目背景 从前有个荣光的王国,小 A 是里面的国王,今天他要赐予他的子民以仓廪。 题目描述 在一条街上有 n n n 个饭店。小 A 站在这条街的最左端。 第 i i i 个饭店离这条街最左端的距离是 a i a_i ai,它所售卖的菜品的美味…...
MATLAB中matfile用法
目录 语法 说明 示例 创建 MAT 文件对象 启用对 MAT 文件的写访问权限 加载整个变量 将整个变量保存至现有 MAT 文件 加载和保存部分变量 确定变量大小 参数说明 局限性 提示 matfile的功能是访问和更改 MAT 文件中的变量,而不必将文件加载到内存中。 …...

Spring之Spring Bean的生命周期
Spring Bean的生命周期 通过BeanDefinition获取bean的定义信息调用构造函数实例化beanBean的依赖注入处理Aware接口(BeanNameAware、BeanFactoryAware、ApplicationContextAware)Bean的后置处理器BeanPostProcessor-前置初始化方法(Initiali…...

OSINT 开源情报中的地理定位方法
了解 OSINT 中的地理定位技术、如何获取地理位置数据以及如何将地理定位用于各种调查场景。 OSINT 中的地理定位基础知识 OSINT 代表开源情报,指的是从免费公共来源合法收集的有关个人或组织的信息。这包括在互联网上以及书籍、公共图书馆报告、报纸文章、新闻稿、…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...

分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...