c++ 友元函数 友元类
1. 友元函数
1.1 简介
友元函数是在类的声明中声明的非成员函数,它被授予访问类的私有成员的权限。这意味着友元函数可以访问类的私有成员变量和私有成员函数,即使它们不是类的成员。
一个类中,可以将其他类或者函数声明为该类的友元,使得这些友元函数能够访问该类的私有成员和受保护成员。
1.2 特点
- 友元函数可以直接访问类的私有成员和受保护成员,包括私有成员变量和私有成员函数,无需通过对象或者类的接口来访问。
- 友元函数在声明时需要在类内部进行声明,并使用关键字
friend
进行修饰。但它不是类的成员函数,因此它在类的作用域之外定义和实现 - 友元关系是单向的:如果A是B的友元,那么B不一定是A的友元。
- 不继承权限,友元函数的权限仅限于声明它的类,而不会被派生类继承。
1.3 使用场景
- 访问私有成员
当需要在某个外部函数中直接访问一个类的私有成员时,可以将该函数声明为友元函数。
#include <iostream>class MyClass {
private:int privateData;public:MyClass(int data) : privateData(data) {}friend void printPrivateData(const MyClass& obj);
};void printPrivateData(const MyClass& obj) {std::cout << "Private data: " << obj.privateData << std::endl;
}int main() {MyClass obj(42);printPrivateData(obj); // 调用友元函数访问私有成员return 0;
}
- 实现操作符重载
#include <iostream>class Complex {
private:double real;double imaginary;public:Complex(double r, double i) : real(r), imaginary(i) {}friend std::ostream& operator<<(std::ostream& os, const Complex& obj);
};std::ostream& operator<<(std::ostream& os, const Complex& obj) {os << obj.real << " + " << obj.imaginary << "i";return os;
}int main() {Complex c(3.5, 2.5);std::cout << "Complex number: " << c << std::endl; // 使用友元函数重载输出操作符return 0;
}
声明了一个友元函数operator<<
,用于重载输出操作符<<
,以便能够以自定义的方式打印Complex类的对象。在main函数中,我们创建了一个Complex对象c,并使用std::cout和友元函数operator<<来打印该对象的值。
3. 提供类之间的非成员函数接口
如果两个类之间需要共享信息或者互相调用对方的非公开成员,可以使用友元关系。
#include <iostream>class ClassB;class ClassA {
private:int data;public:ClassA(int d) : data(d) {}friend void processData(const ClassA& objA, const ClassB& objB);
};class ClassB {
private:int data;public:ClassB(int d) : data(d) {}friend void processData(const ClassA& objA, const ClassB& objB);
};void processData(const ClassA& objA, const ClassB& objB) {std::cout << "Data from ClassA: " << objA.data << std::endl;std::cout << "Data from ClassB: " << objB.data << std::endl;
}int main() {ClassA objA(42);ClassB objB(24);processData(objA, objB); // 调用友元函数处理两个类的数据return 0;
}
定义了两个类ClassA和ClassB,并在它们之间声明了一个友元函数processData
。这个函数可以访问ClassA和ClassB的私有成员变量,并在函数中处理这些数据。在main函数中,我们创建了一个ClassA对象objA和一个ClassB对象objB,然后调用友元函数processData来处理这两个类的数据。
1.4 注意
- 友元关系破坏了封装性原则,因此应谨慎使用。过度依赖友元关系可能会导致代码不易维护和扩展。
- 友元关系没有继承性质,只限于被声明为友元的类或者函数能够访问相应的成员。
2. 友元类
2.1 简介
C++中的友元类(friend class)是指一个类可以将另一个类声明为友元,从而允许友元类访问其私有成员。
2.2 特点
- 友元关系是单向的:如果类A是类B的友元,则只有类B能够访问类A的私有和保护成员,反之则不成立。
- 友元关系不可传递:即使类A是类B的友元,而类B又是类C的友元,但并不能推导出类A是类C的友元。
- 友元关系没有继承性:即使派生类继承了基类,基类中声明为友元的其他类并不会自动成为派生类的友元。
2.3 使用场景
- 信息封装:当一个类需要将其私有成员暴露给另一个类以实现特定功能时,可以将另一个类声明为友元类。这样,友元类就可以直接访问声明它的类的私有成员,从而实现类之间的信息封装。
- 成员访问优化:有时候,多个类之间需要频繁访问彼此的私有成员,而不希望通过公有接口进行访问。在这种情况下,可以将这些类声明为友元类,以提高成员访问的效率。
代码:
class FriendClass {
private:int privateData;public:FriendClass(int data) : privateData(data) {}friend class MyClass;
};class MyClass {
public:void accessFriendData(const FriendClass& obj) {int data = obj.privateData; // 友元类可以访问FriendClass的私有成员}
};int main() {FriendClass obj(42);MyClass myObj;myObj.accessFriendData(obj); // MyClass通过友元类访问FriendClass的私有成员return 0;
}
上述示例中,定义了两个类FriendClass和MyClass。FriendClass将MyClass声明为友元类,从而允许MyClass访问FriendClass的私有成员变量privateData。在MyClass中,我们定义了一个成员函数accessFriendData,它通过友元类的权限访问FriendClass的私有成员。在main函数中,创建了FriendClass的对象obj和MyClass的对象myObj,并通过myObj调用accessFriendData来访问FriendClass的私有成员。
两个代码互为友元,代码:
#include <iostream>using namespace std;class B; // 前向声明class A {
private:int privateDataA;
public:A() : privateDataA() {};friend class B; // 声明B为A的友元类void displayPrivateData(const B& b);
};class B {
private:int privateDataB;
public:B() : privateDataB(10) {};friend class A; // 声明A为B的友元类void setPrivateData( A & a, int data) {a.privateDataA = data; // 可以直接访问A中的私有成员cout << "Successfully set private data of A from B: " << a.privateDataA << endl;}
};void A::displayPrivateData(const B & b) {cout << "Accessing private data of B from A: " << b.privateDataB << endl;
}int main() {A a;B b;b.setPrivateData(a, 42); // 通过B类的成员函数修改A类的私有成员数据a.displayPrivateData(b); // 通过A类的成员函数访问B类的私有成员数据return 0;
}
运行结果:
Successfully set private data of A from B: 42
Accessing private data of B from A: 10
A和B是两个类。通过将彼此声明为友元类,它们可以直接访问对方的私有成员。在主函数中,我们创建了一个A对象a和一个B对象b,并使用友元函数setPrivateData从b中修改了a的私有成员数据,并使用友元函数displayPrivateData从a中访问了b的私有成员数据。
相关文章:
c++ 友元函数 友元类
1. 友元函数 1.1 简介 友元函数是在类的声明中声明的非成员函数,它被授予访问类的私有成员的权限。这意味着友元函数可以访问类的私有成员变量和私有成员函数,即使它们不是类的成员。 一个类中,可以将其他类或者函数声明为该类的友元&#…...
Spring推断构造器源码分析
Spring中bean虽然可以通过多种方式(Supplier接口、FactoryMethod、构造器)创建bean的实例对象,但是使用最多的还是通过构造器创建对象实例,也是我们最熟悉的创建对象的方式。如果有多个构造器时,那Spring是如何推断使用…...

十五、【历史记录画笔工具组】
文章目录 历史记录画笔工具历史记录艺术画笔工具 历史记录画笔工具 历史记录画笔工具很简单,就是将画笔工具嗯,涂抹过的修改过的地方,然后用历史记录画笔工具重新修改回来,比如我们将三叠美元中的一叠用画笔工具先涂抹掉…...
Spark上使用pandas API快速入门
文章最前: 我是Octopus,这个名字来源于我的中文名--章鱼;我热爱编程、热爱算法、热爱开源。所有源码在我的个人github ;这博客是记录我学习的点点滴滴,如果您对 Python、Java、AI、算法有兴趣,可以关注我的…...
【WebRTC---源码篇】(十:零)WEBRTC/StreamStatisticianImpl持续更新中)
StreamStatisticianImpl是WebRTC的一个内部实现类,用于统计和管理媒体流的各种统计信息。 StreamStatisticianImpl负责记录和计算以下统计数据: 1. 带宽统计:记录媒体流的发送和接收带宽信息,包括发送比特率、接收比特率、发送丢…...
调用Lua脚本tostring(xxx)报attempt to call a nil value (global ‘tostring‘
在c程序里调用Lua脚本, 脚本中用到了转字符串 tostring(xxx) str "test" function output(a,b,c)d "a:"..tostring(a).."b:"..tostring(b).."c"..tostring(c)return d end 实际运行会报错: attempt to call a nil v…...

PBA.客户需求分析 需求管理
一、客户需求分析 1 需求的三个层次: Requirement/Wants/Pains 大部分人认为,产品满足不了客户需要,是因为客户告知的需求是错误的,这听起来有一些道理,却没有任何意义。不同角色对于需求的理解是不一样的。在客户的需求和厂家的…...

Kafka进阶
Kafka进阶 Kafka事务 kafka的事务机制是指kafka支持跨多个主题和分区的原子性写入,即在一个事务中发送的所有消息要么全部成功,要么全部失败。 kafka的事务机制涉及到以下几个方面: 事务生产者(transactional producer&#x…...
大数计算:e^1000/300!
1.问题:大数计算可能超出数据类型范围 当单独计算 ,因为 ,double的最大取值为1.79769e308,所以 肯定超过了double的表示范围。 同样,对于300!也是如此。 那我们应该怎么去计算和存储结果呢?…...

力扣164最大间距
1.前言 因为昨天写了一个基数排序,今天我来写一道用基数排序实现的题解,希望可以帮助你理解基数排序。 这个题本身不难,就是线性时间和线性额外空间(O(n))的算法,有点难实现 基数排序的时间复杂度是O(d*(nradix)),其中…...

聚观早报 | “百度世界2023”即将举办;2024款岚图梦想家上市
【聚观365】10月13日消息 “百度世界2023”即将举办 2024款岚图梦想家上市 腾势D9用户超10万 华为发布新一代GigaGreen Radio OpenAI拟进行重大更新 “百度世界2023”即将举办 “百度世界2023”将于10月17日在北京首钢园举办。届时,百度创始人、董事长兼首席执…...
Windows 应用程序监控重启
执行思路 1.定时关闭可执行程序,2.再通过定时监控启动可执行程序 定时启动关闭程序.bat echo off cd "D:\xxxx\" :: 可执行程序目录 Start "" /b xxxx.exe :: 可执行程序 timeout /T 600 /nobreak >nul :: 600秒 taskkill /IM xxxx.exe /…...

springboot 通过url下载文件并上传到OSS
DEMO流程 传入一个需要下载并上传的url地址下载文件上传文件并返回OSS的url地址 springboot pom文件依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w…...

docker创建elasticsearch、elasticsearch-head部署及简单操作
elasticsearch部署 1 拉取elasticsearch镜像 docker pull elasticsearch:7.7.0 2 创建文件映射路径 mkdir /mydata/elasticsearch/data mkdir /mydata/elasticsearch/plugins mkdir /mydata/elasticsearch/config 3 文件夹授权 chmod 777 /mydata/elastic…...

竞赛选题 深度学习+python+opencv实现动物识别 - 图像识别
文章目录 0 前言1 课题背景2 实现效果3 卷积神经网络3.1卷积层3.2 池化层3.3 激活函数:3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 inception_v3网络5 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 *…...

Codeforces Round 903 (Div. 3)ABCDE
Codeforces Round 903 (Div. 3)ABCDE 目录 A. Dont Try to Count题目大意思路核心代码 B. Three Threadlets题目大意思路核心代码 C. Perfect Square题目大意思路核心代码 D. Divide and Equalize题目大意思路核心代码 E. Block Sequence题目大意思路核心代码 A. Don’t Try t…...
C# 与 C/C++ 的交互
什么是平台调用 (P/Invoke) P/Invoke 是可用于从托管代码访问非托管库中的结构、回调和函数的一种技术。 托管代码与非托管的区别 托管代码和非托管代码的主要区别是内存管理方式和对计算机资源的访问方式。托管代码通常运行在托管环境中,如 mono 或 java 虚拟机等…...

新版Android Studio搜索不到Lombok以及无法安装Lombok插件的问题
前言 在最近新版本的Android Studio中,使用插件时,在插件市场无法找到Lombox Plugin,具体表现如下图所示: 1、操作步骤: (1)打开Android Studio->Settings->Plugins,搜索Lom…...
BST二叉搜索树
文章目录 概述实现创建节点查找节点增加节点查找后驱值根据关键词删除找到树中所有小于key的节点的value 概述 二叉搜索树,它具有以下的特性,树节点具有一个key属性,不同节点之间key是不能重复的,对于任意一个节点,它…...
【Leetcode】211. 添加与搜索单词 - 数据结构设计
一、题目 1、题目描述 请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。 实现词典类 WordDictionary : WordDictionary() 初始化词典对象void addWord(word) 将 word 添加到数据结构中,之后可以对它…...

【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...

selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...

算术操作符与类型转换:从基础到精通
目录 前言:从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符:、-、*、/、% 赋值操作符:和复合赋值 单⽬操作符:、--、、- 前言:从基础到实践——探索运算符与类型转换的奥秘 在先前的文…...

从零开始了解数据采集(二十八)——制造业数字孪生
近年来,我国的工业领域正经历一场前所未有的数字化变革,从“双碳目标”到工业互联网平台的推广,国家政策和市场需求共同推动了制造业的升级。在这场变革中,数字孪生技术成为备受关注的关键工具,它不仅让企业“看见”设…...

鸿蒙Navigation路由导航-基本使用介绍
1. Navigation介绍 Navigation组件是路由导航的根视图容器,一般作为Page页面的根容器使用,其内部默认包含了标题栏、内容区和工具栏,其中内容区默认首页显示导航内容(Navigation的子组件)或非首页显示(Nav…...
【仿生机器人】刀剑神域——爱丽丝苏醒计划,需求文档
仿生机器人"爱丽丝"系统架构设计需求文档 一、硬件基础 已完成头部和颈部硬件搭建 25个舵机驱动表情系统 颈部旋转功能 眼部摄像头(视觉输入) 麦克风阵列(听觉输入) 颈部发声装置(语音输出)…...