0

0

C++ 友元函数与友元类是什么?(如何在保证封装性的前提下授权访问)

尼克

尼克

发布时间:2026-02-12 18:17:02

|

975人浏览过

|

来源于php中文网

原创

友元函数能访问private成员是因为编译器将其视为类内授权的“访问白名单”,而非绕过封装;声明必须在类内显式写出完整签名,且不隐含this指针。

c++ 友元函数与友元类是什么?(如何在保证封装性的前提下授权访问)

友元函数为什么能访问 private 成员?

因为编译器在生成符号时,会把友元声明当作一种「访问白名单」,不走常规的访问控制检查。它不是绕过封装,而是你主动在类定义里签了授权书。

常见错误现象:error: 'x' is private within this context —— 往往是忘了在类内加 friend 声明,或者声明和实现的函数签名不一致(比如 const 修饰、参数类型差一个 const &)。

实操建议:

  • 友元函数必须在类内部用 friend 显式声明,声明位置不影响,但不能只在类外定义
  • 声明时写全签名:比如 friend void print(const MyClass&);,不能省略 const 或引用符
  • 友元函数本身不属于类,不隐含 this,也不能直接用 name 访问成员,得通过参数对象来访问,比如 obj.private_member

友元类和“全权委托”陷阱

声明 friend class Helper; 后,Helper 的所有成员函数(包括静态、模板、嵌套类里的函数)都能访问该类的 private 成员——这不是按需授权,而是整张通行证。

立即学习C++免费学习笔记(深入)”;

使用场景有限:常见于紧密耦合的配套类,比如 Iterator 和容器类、Proxy 和被代理类。但别用来“偷懒解耦”,否则封装形同虚设。

容易踩的坑:

  • 友元关系不可继承:基类把某类设为友元,派生类的 private 成员对那个友元类仍是不可见的
  • 友元关系不传递:A 是 B 的友元,B 是 C 的友元,A 不能因此访问 C 的 private
  • 头文件依赖爆炸:友元类名必须在声明处可见,常导致头文件互相包含,建议前向声明 + 分离定义

替代方案比友元更安全的三个时机

友元不是万能钥匙,多数时候有更可控的选择。

PpcyAI
PpcyAI

泡泡次元AI-游戏美术AI创作平台,低门槛上手,高度可控,让你的创意秒速落地

下载

当出现以下情况,请先考虑替代而非加 friend

  • 只想读某个值 → 提供 get_x() 这样的 const 成员函数,而不是开放整个状态
  • 需要构造或修改内部结构 → 用工厂函数或命名构造器(如 MyClass::from_raw_data(...)),把逻辑收束在类内
  • 两个类频繁交换私有数据 → 检查是否该合并,或引入中间接口(如 Visitor 模式),避免双向友元

性能上没差别,但可维护性差很多:加一个 friend 很快,删它可能要改十几处代码,因为没人记得谁依赖了那个“后门”。

友元在模板中的声明特别容易失效

模板类的友元声明必须和实例化后的签名完全匹配,而编译器不会自动推导模板参数。这是最隐蔽的坑。

典型错误:

template<typename T>
class Box {
    T val;
    friend void f(Box&); // ❌ 错!编译器不知道 T 是什么
};

正确写法有两种:

  • 显式指定模板参数:friend void f<int>(Box<int>&);</int></int>(只对特定实例有效)
  • 声明为模板友元:template<typename u> friend void f(Box<u>&);</u></typename>(推荐,但注意这会让所有 f<t></t> 都获得访问权)
  • 如果友元本身也是模板,还需确保它在友元声明前已声明(否则编译器不认识)

跨翻译单元时尤其麻烦:模板友元的定义必须在头文件中,否则链接失败,且不能用 extern template 优化。

复杂点在于,友元模板的访问权限是按实例算的——Box<int></int>Box<double></double> 是两个独立类,彼此的友元声明互不影响。这点很容易被忽略。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
python中print函数的用法
python中print函数的用法

python中print函数的语法是“print(value1, value2, ..., sep=' ', end=' ', file=sys.stdout, flush=False)”。本专题为大家提供print相关的文章、下载、课程内容,供大家免费下载体验。

191

2023.09.27

python print用法与作用
python print用法与作用

本专题整合了python print的用法、作用、函数功能相关内容,阅读专题下面的文章了解更多详细教程。

11

2026.02.03

scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

351

2023.10.18

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

326

2023.10.25

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

542

2023.09.20

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

708

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

559

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

193

2025.08.29

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

4

2026.02.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 9.3万人学习

C 教程
C 教程

共75课时 | 4.7万人学习

C++教程
C++教程

共115课时 | 17.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号