当前位置: 首页 > news >正文

c++ 友元函数 友元类

1. 友元函数

1.1 简介

友元函数是在类的声明中声明的非成员函数,它被授予访问类的私有成员的权限。这意味着友元函数可以访问类的私有成员变量和私有成员函数,即使它们不是类的成员。
一个类中,可以将其他类或者函数声明为该类的友元,使得这些友元函数能够访问该类的私有成员和受保护成员。

1.2 特点

  1. 友元函数可以直接访问类的私有成员和受保护成员,包括私有成员变量和私有成员函数,无需通过对象或者类的接口来访问。
  2. 友元函数在声明时需要在类内部进行声明,并使用关键字 friend 进行修饰。但它不是类的成员函数,因此它在类的作用域之外定义和实现
  3. 友元关系是单向的:如果A是B的友元,那么B不一定是A的友元。
  4. 不继承权限,友元函数的权限仅限于声明它的类,而不会被派生类继承。

1.3 使用场景

  1. 访问私有成员
    当需要在某个外部函数中直接访问一个类的私有成员时,可以将该函数声明为友元函数。
#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;
}
  1. 实现操作符重载
#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 注意

  1. 友元关系破坏了封装性原则,因此应谨慎使用。过度依赖友元关系可能会导致代码不易维护和扩展。
  2. 友元关系没有继承性质,只限于被声明为友元的类或者函数能够访问相应的成员。

2. 友元类

2.1 简介

C++中的友元类(friend class)是指一个类可以将另一个类声明为友元,从而允许友元类访问其私有成员。

2.2 特点

  1. 友元关系是单向的:如果类A是类B的友元,则只有类B能够访问类A的私有和保护成员,反之则不成立。
  2. 友元关系不可传递:即使类A是类B的友元,而类B又是类C的友元,但并不能推导出类A是类C的友元。
  3. 友元关系没有继承性:即使派生类继承了基类,基类中声明为友元的其他类并不会自动成为派生类的友元。

2.3 使用场景

  1. 信息封装:当一个类需要将其私有成员暴露给另一个类以实现特定功能时,可以将另一个类声明为友元类。这样,友元类就可以直接访问声明它的类的私有成员,从而实现类之间的信息封装。
  2. 成员访问优化:有时候,多个类之间需要频繁访问彼此的私有成员,而不希望通过公有接口进行访问。在这种情况下,可以将这些类声明为友元类,以提高成员访问的效率。

代码:

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 简介 友元函数是在类的声明中声明的非成员函数&#xff0c;它被授予访问类的私有成员的权限。这意味着友元函数可以访问类的私有成员变量和私有成员函数&#xff0c;即使它们不是类的成员。 一个类中&#xff0c;可以将其他类或者函数声明为该类的友元&#…...

Spring推断构造器源码分析

Spring中bean虽然可以通过多种方式&#xff08;Supplier接口、FactoryMethod、构造器&#xff09;创建bean的实例对象&#xff0c;但是使用最多的还是通过构造器创建对象实例&#xff0c;也是我们最熟悉的创建对象的方式。如果有多个构造器时&#xff0c;那Spring是如何推断使用…...

十五、【历史记录画笔工具组】

文章目录 历史记录画笔工具历史记录艺术画笔工具 历史记录画笔工具 历史记录画笔工具很简单&#xff0c;就是将画笔工具嗯&#xff0c;涂抹过的修改过的地方&#xff0c;然后用历史记录画笔工具重新修改回来&#xff0c;比如我们将三叠美元中的一叠用画笔工具先涂抹掉&#xf…...

Spark上使用pandas API快速入门

文章最前&#xff1a; 我是Octopus&#xff0c;这个名字来源于我的中文名--章鱼&#xff1b;我热爱编程、热爱算法、热爱开源。所有源码在我的个人github &#xff1b;这博客是记录我学习的点点滴滴&#xff0c;如果您对 Python、Java、AI、算法有兴趣&#xff0c;可以关注我的…...

【WebRTC---源码篇】(十:零)WEBRTC/StreamStatisticianImpl持续更新中)

StreamStatisticianImpl是WebRTC的一个内部实现类&#xff0c;用于统计和管理媒体流的各种统计信息。 StreamStatisticianImpl负责记录和计算以下统计数据&#xff1a; 1. 带宽统计&#xff1a;记录媒体流的发送和接收带宽信息&#xff0c;包括发送比特率、接收比特率、发送丢…...

​调用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 实际运行会报错&#xff1a; attempt to call a nil v…...

PBA.客户需求分析 需求管理

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

Kafka进阶

Kafka进阶 Kafka事务 kafka的事务机制是指kafka支持跨多个主题和分区的原子性写入&#xff0c;即在一个事务中发送的所有消息要么全部成功&#xff0c;要么全部失败。 kafka的事务机制涉及到以下几个方面&#xff1a; 事务生产者&#xff08;transactional producer&#x…...

大数计算:e^1000/300!

1.问题&#xff1a;大数计算可能超出数据类型范围 当单独计算 &#xff0c;因为 &#xff0c;double的最大取值为1.79769e308&#xff0c;所以 肯定超过了double的表示范围。 同样&#xff0c;对于300&#xff01;也是如此。 那我们应该怎么去计算和存储结果呢&#xff1f;…...

力扣164最大间距

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

聚观早报 | “百度世界2023”即将举办;2024款岚图梦想家上市

【聚观365】10月13日消息 “百度世界2023”即将举办 2024款岚图梦想家上市 腾势D9用户超10万 华为发布新一代GigaGreen Radio OpenAI拟进行重大更新 “百度世界2023”即将举办 “百度世界2023”将于10月17日在北京首钢园举办。届时&#xff0c;百度创始人、董事长兼首席执…...

Windows 应用程序监控重启

执行思路 1.定时关闭可执行程序&#xff0c;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 激活函数&#xff1a;3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 inception_v3网络5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; *…...

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 是可用于从托管代码访问非托管库中的结构、回调和函数的一种技术。 托管代码与非托管的区别 托管代码和非托管代码的主要区别是内存管理方式和对计算机资源的访问方式。托管代码通常运行在托管环境中&#xff0c;如 mono 或 java 虚拟机等…...

新版Android Studio搜索不到Lombok以及无法安装Lombok插件的问题

前言 在最近新版本的Android Studio中&#xff0c;使用插件时&#xff0c;在插件市场无法找到Lombox Plugin&#xff0c;具体表现如下图所示&#xff1a; 1、操作步骤&#xff1a; &#xff08;1&#xff09;打开Android Studio->Settings->Plugins&#xff0c;搜索Lom…...

BST二叉搜索树

文章目录 概述实现创建节点查找节点增加节点查找后驱值根据关键词删除找到树中所有小于key的节点的value 概述 二叉搜索树&#xff0c;它具有以下的特性&#xff0c;树节点具有一个key属性&#xff0c;不同节点之间key是不能重复的&#xff0c;对于任意一个节点&#xff0c;它…...

【Leetcode】211. 添加与搜索单词 - 数据结构设计

一、题目 1、题目描述 请你设计一个数据结构&#xff0c;支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。 实现词典类 WordDictionary &#xff1a; WordDictionary() 初始化词典对象void addWord(word) 将 word 添加到数据结构中&#xff0c;之后可以对它…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

R语言速释制剂QBD解决方案之三

本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...

tomcat指定使用的jdk版本

说明 有时候需要对tomcat配置指定的jdk版本号&#xff0c;此时&#xff0c;我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...

Vue 模板语句的数据来源

&#x1f9e9; Vue 模板语句的数据来源&#xff1a;全方位解析 Vue 模板&#xff08;<template> 部分&#xff09;中的表达式、指令绑定&#xff08;如 v-bind, v-on&#xff09;和插值&#xff08;{{ }}&#xff09;都在一个特定的作用域内求值。这个作用域由当前 组件…...

stm32wle5 lpuart DMA数据不接收

配置波特率9600时&#xff0c;需要使用外部低速晶振...

MySQL体系架构解析(三):MySQL目录与启动配置全解析

MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录&#xff0c;这个目录下存放着许多可执行文件。与其他系统的可执行文件类似&#xff0c;这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中&#xff0c;用…...

Tauri2学习笔记

教程地址&#xff1a;https://www.bilibili.com/video/BV1Ca411N7mF?spm_id_from333.788.player.switch&vd_source707ec8983cc32e6e065d5496a7f79ee6 官方指引&#xff1a;https://tauri.app/zh-cn/start/ 目前Tauri2的教程视频不多&#xff0c;我按照Tauri1的教程来学习&…...