C++ 中的友元函数和友元类

友元函数(Friend Function)

友元函数 是被声明为某个类的“朋友”的普通函数或类的成员函数。友元函数可以访问该类的私有成员和保护成员。

语法:

class ClassName {friend ReturnType FriendFunctionName(Arguments);
private:int privateMember;
protected:int protectedMember;
public:int publicMember;
};

特点:
  1. 友元函数不是类的成员函数,但可以访问类的私有和保护成员。
  2. 需要在类内部用 friend 关键字显式声明。
  3. 通常用于操作类的内部数据而不破坏封装性,比如实现运算符重载。
示例:

#include <iostream>
using namespace std;class Box {
private:double width;
public:Box(double w) : width(w) {}// 声明友元函数friend void printWidth(Box b);
};// 定义友元函数
void printWidth(Box b) {
    cout << "Width of box: " << b.width << endl;
}int main() {
    Box b(10.5);printWidth(b); // 调用友元函数return 0;
}

友元类(Friend Class)

友元类 是一个类声明为另一个类的朋友。友元类的所有成员函数都可以访问另一个类的私有成员和保护成员。

语法:

class ClassB; // 前向声明class ClassA {friend class ClassB; // 声明 ClassB 为友元类
private:int privateMemberA;
protected:int protectedMemberA;
};class ClassB {
public:void accessClassA(ClassA& a) {
        a.privateMemberA = 10; // 访问 ClassA 的私有成员
        a.protectedMemberA = 20; // 访问 ClassA 的保护成员}
};

特点:
  1. 被声明为友元的类可以访问另一个类的所有成员,包括私有和保护成员。
  2. 需要在类内部用 friend class ClassName 声明。
  3. 友元关系是单向的,不是双向的。例如,ClassBClassA 的友元,但 ClassA 不是 ClassB 的友元,除非显式声明。
示例:

#include <iostream>
using namespace std;class Box;class Printer {
public:void printBoxVolume(Box& b);
};class Box {
private:double length;double width;double height;friend class Printer; // Printer 是 Box 的友元类
public:Box(double l, double w, double h) : length(l), width(w), height(h) {}
};void Printer::printBoxVolume(Box& b) {double volume = b.length * b.width * b.height;
    cout << "Volume of box: " << volume << endl;
}int main() {
    Box b(10.0, 5.0, 3.0);
    Printer p;
    p.printBoxVolume(b); // 调用友元类的方法return 0;
}

友元的优缺点

优点:
  1. 提高了类之间的访问能力,在特殊情况下很方便,例如运算符重载。
  2. 保持了接口简单,避免通过 public 方法间接访问私有数据。
缺点:
  1. 破坏了封装性,因为友元函数和类可以直接访问私有成员。
  2. 过度使用友元可能导致代码的耦合度增加。

友元的作用

C++ 中的友元机制通过 friend 关键字为某些函数或类提供访问另一个类的私有和保护成员的权限。它的主要作用包括以下几个方面:

1. 允许外部函数访问类的私有/保护成员

在保持类成员私有的同时,为特定的外部函数提供直接访问权限,例如:

  • 运算符重载: 很多情况下,需要外部函数直接操作类对象的私有数据。
  • 数据操作: 当需要高效操作类的内部数据时,可以通过友元函数简化接口。

示例:运算符重载

#include <iostream>
using namespace std;class Complex {
private:double real, imag;
public:Complex(double r, double i) : real(r), imag(i) {}// 声明友元函数friend Complex operator+(const Complex& c1, const Complex& c2);
};Complex operator+(const Complex& c1, const Complex& c2) {return Complex(c1.real + c2.real, c1.imag + c2.imag);
}

2. 在多个类之间共享私有数据

当多个类需要共享彼此的私有数据时,使用友元类可以让某个类直接访问另一个类的私有成员,避免通过公共接口间接访问。

示例:类之间的协作

#include <iostream>
using namespace std;class Box;class Calculator {
public:double calculateVolume(const Box& b);
};class Box {
private:double length, width, height;friend class Calculator; // Calculator 是 Box 的友元类
public:Box(double l, double w, double h) : length(l), width(w), height(h) {}
};double Calculator::calculateVolume(const Box& b) {return b.length * b.width * b.height; // 直接访问私有成员
}

3. 简化类的接口设计

通过友元,避免暴露多余的公共成员函数,使类的接口更简洁,从而提高封装性。例如,在操作复杂内部逻辑时,可以通过友元直接访问,而不需要增加过多的访问器方法。

友元的注意事项

1. 友元破坏了封装性

友元函数或类能够访问类的私有和保护成员,这违背了封装的基本原则。如果滥用友元,可能导致代码结构混乱,增加维护成本。

解决方式:

  • 尽量将友元函数的使用限制在必要范围内,仅用于实现类的核心功能。
  • 在类设计中,优先考虑是否可以通过公共接口完成同样的功能。

2. 友元关系是单向的

友元关系并非双向。例如,如果类 A 是类 B 的友元,A 可以访问 B 的私有成员,但 B 无法访问 A 的私有成员,除非 B 也显式声明 A 为友元。

3. 友元关系不可继承

友元关系不能被子类继承。例如,如果类 A 是类 B 的友元,AB 的派生类没有访问权限。

4. 友元关系需要显式声明

必须在类中使用 friend 关键字显式声明友元关系。声明位置通常在类定义的私有或保护部分,但其作用域是整个类。

5. 友元不能滥用

友元功能提供了访问权限,但不代表应该随意使用,过度的友元使用可能会造成代码耦合性过高,降低代码的模块化程度。

友元使用的最佳实践

  1. 优先考虑公共接口: 如果可以通过公共接口实现相同功能,避免使用友元。
  2. 明确职责: 使用友元时,明确为什么需要友元,而不是为了方便直接访问私有数据。
  3. 局部使用: 仅为特定功能声明友元,例如特定函数或类之间需要访问时使用。
  4. 减少依赖: 友元关系增加了耦合性,尽量减少对友元的依赖。

总结

友元是 C++ 中一种灵活的访问权限控制机制,能够增强类的协作能力,简化类设计。但使用时应权衡封装性和灵活性,避免滥用友元造成不必要的耦合和复杂性。

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

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

相关文章

C++的IO流

目录 1. C语言的输入与输出 2. 流是什么 3. CIO流 3.1 C标准IO流 3.2 C文件IO流 4 stringstream的简单介绍 1. 将数值类型数据格式化为字符串 2. 字符串拼接 3. 序列化和反序列化结构数据 1. C语言的输入与输出 C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。…

青训营刷题笔记11

水一个简单题&#xff1a; 问题描述 小C定义了一个“完美偶数”。一个正整数 xx 被认为是完美偶数需要满足以下两个条件&#xff1a; xx 是偶数&#xff1b;xx 的值在区间 [l,r][l,r] 之间。 现在&#xff0c;小C有一个长度为 nn 的数组 aa&#xff0c;她想知道在这个数组中…

游戏+AI的发展历程,AI技术在游戏行业的应用有哪些?

人工智能&#xff08;AI&#xff09;与游戏的结合&#xff0c;不仅是技术进步的体现&#xff0c;更是人类智慧的延伸。从最初的简单规则到如今的复杂决策系统&#xff0c;AI在游戏领域的发展历史可谓波澜壮阔。 早在2001年&#xff0c;就有研究指出游戏人工智能领域&#xff0…

Vue.js 插槽 Slots 实际应用 最近重构项目的时候遇到的...

前端开发中 插槽 Slots 是一个重要的概念 我们可以查看一下vue.js的官方文档 https://cn.vuejs.org/guide/components/slots 类似于连接通道一样 可以把核心代码逻辑搬到另外的地方 做一个引用 而原先的地方可能并不能这样书写 对于这个概念我在vue的官方文档里面找到了…

Windows11在WSL中安装QEMU-KVM

Windows11在WSL中安装QEMU-KVM 检查系统信息WSL检测安装所需软件端口转发 检查系统信息 打开设置-系统-系统信息&#xff08;拉到最下面&#xff09;&#xff0c;我的是 版本 Windows 11 专业版 版本号 24H2 安装日期 ‎2024/‎11/‎13 操作系统版本 26100.2314 体验 Windows …

【东莞石碣】戴尔R740服务器维修raid硬盘问题

1&#xff1a;石碣某塑料工厂下午报修一台戴尔R740服务器硬盘故障&#xff0c;催的还比较着急。 2&#xff1a;工程师经过跟用户确认故障的问题以及故障服务器型号和故障硬盘型号&#xff0c;产品和配件确认好后&#xff0c;公司仓库确认有该款硬盘现货&#xff0c;DELL 12T S…

SpringBoot学习笔记(一)

一、Spring Boot概述 &#xff08;一&#xff09;微服务概述 1、微服务 微服务&#xff08;英语&#xff1a;Microservices&#xff09;是一种软件架构风格&#xff0c;它是以专注于单一责任与功能的小型功能区块 (Small Building Blocks) 为基础&#xff0c;利用模块化的方式…

SD模型微调之LoRA

​ &#x1f33a;系列文章推荐&#x1f33a; 扩散模型系列文章正在持续的更新&#xff0c;更新节奏如下&#xff0c;先更新SD模型讲解&#xff0c;再更新相关的微调方法文章&#xff0c;敬请期待&#xff01;&#xff01;&#xff01;&#xff08;本文及其之前的文章均已更新&a…

手机远程控制电脑,让办公更快捷

在数字化办公的浪潮下&#xff0c;远程控制软件已成为连接工作与生活的桥梁。它使得用户能够通过一台设备&#xff08;主控端&#xff09;来操作另一台设备&#xff08;被控端&#xff09;&#xff0c;无论它们是否位于同一局域网内。这种软件广泛应用于远程办公、手机远程控制…

【Three.js基础学习】26. Animated galaxy

前言 shaders实现星系 课程回顾 使用顶点着色器为每个粒子设置动画 a属性 &#xff0c; u制服 &#xff0c;v变化 像素比&#xff1a;window.devicePixelRatio 自动从渲染器检索像素比 renderer.getPixelRatio() 如何尺寸衰减&#xff0c; 放大缩小视角时&#xff0c;粒子都是同…

基于Springboot + Vue的旧物置换网站管理系统(源码+lw+部署讲解+PPT)

前言 详细视频演示 论文参考 系统介绍 系统概述 核心功能 具体实现截图 1. 首页功能 2. 旧物信息功能 3. 网站公告功能 4. 用户管理功能&#xff08;管理员端&#xff09; 5. 置换交易管理功能 技术栈 后端框架SpringBoot 前端框架Vue 持久层框架MyBatis-Plus …

新书速览|循序渐进Spark大数据应用开发

《循序渐进Spark大数据应用开发》 本书内容 《循序渐进Spark大数据应用开发》结合作者一线开发实践&#xff0c;循序渐进地介绍了新版Apache Spark 3.x的开发技术。全书共10章&#xff0c;第1章和第2章主要介绍Spark的基本概念、安装&#xff0c;并演示如何编写最简单的Spark程…

一道算法期末应用题及解答

1&#xff0e;印刷电路板布线区划分成为n m 个方格&#xff0c;确定连接方格a 到方格b 的最短布线方案。 在布线时&#xff0c;只能沿直线或者直角布线&#xff0c;为避免交叉&#xff0c;已经布线的方格做了封锁标记&#xff0c;其他线路不允许穿过被封锁的方格&#xff0c;某…

2024内科学综合类科技核心期刊汇总

在已经公布的中国科技核心期刊目录&#xff08;2024年版&#xff09;中&#xff0c;5本内科学综合类期刊入选。常笑医学整理了这5本科技核心期刊的详细参数&#xff0c;以及投稿信息&#xff0c;供大家在论文投稿时参考&#xff0c;有需要的赶紧收藏&#xff01; 1.《临床内科…

【网络】Socket编程TCP/UDP序列化和反序列化理解应用层(C++实现)Json::Value

主页&#xff1a;醋溜马桶圈-CSDN博客 专栏&#xff1a;计算机网络原理_醋溜马桶圈的博客-CSDN博客 gitee&#xff1a;mnxcc (mnxcc) - Gitee.com 目录 1.基于Socket的UDP和TCP编程介绍 1.1 基本TCP客户—服务器程序设计基本框架 ​编辑1.2 基本UDP客户—服务器程序设计基本框…

Spring MVC——针对实习面试

目录 Spring MVC什么是Spring MVC&#xff1f;简单介绍下你对Spring MVC的理解&#xff1f;Spring MVC的优点有哪些&#xff1f;Spring MVC的主要组件有哪些&#xff1f;Spring MVC的工作原理或流程是怎样的&#xff1f;Spring MVC常用注解有哪些&#xff1f; Spring MVC 什么是…

硬件工程师之电子元器件—二极管(10)之可变电容和TVS二极管

写在前面 本系列文章主要讲解二极管的相关知识&#xff0c;希望能帮助更多的同学认识和了解二极管。 若有相关问题&#xff0c;欢迎评论沟通&#xff0c;共同进步。(*^▽^*) 二极管 25. 齐纳二极管的动态阻抗 齐纳阻抗是齐纳二极管在传导电流时的等效串联电阻&#xff08;E…

2024-11-19 树与二叉树

一、树的定义和基本语术 1.基本概念&#xff1a;从根节点出发&#xff0c;依次长出各个分支&#xff0c;各个分支也能长出下级分支。&#xff08;根节点无前驱&#xff0c;叶无后继&#xff09;除根节点外&#xff0c;任何一个结点有且仅有一个前驱。 2.树的基本概念&#xff…

【金融风控项目-08】:特征构造

文章目录 1.数据准备1.1 风控建模特征数据1.2 人行征信数据1.3 据之间的内在逻辑 2 样本设计和特征框架2.1 定义观察期样本2.2 数据EDA(Explore Data Analysis)2.3 梳理特征框架 3 特征构造3.1 静态信息和时间截面特征3.2 未来信息问题3.2.1 未来信息案例3.2.2 时间序列特征的未…

docker基础

一 docker整体架构 docker镜像&#xff08;image&#xff09; docker hub类似于maven远程仓库地址&#xff1a; https://hub.docker.com/ 该地址用于搜索并下载地址。 镜像下载命令&#xff1a; docker pull imagename 比如&#xff1a;docker pull to…