友元类仅能访问被明确声明为友元的类的私有成员,不支持继承与传递;典型场景包括容器与迭代器、工厂与构造函数;滥用会破坏封装性并引发依赖问题。

友元类能访问私有成员,但仅限于明确声明的类
友元类不是“开放全部权限”,而是由被访问类主动授予特定访问权。比如 A 类声明 friend class B;,那只有 B 的成员函数(或友元函数)能在定义中直接访问 A 的 private 和 protected 成员——其他类哪怕继承自 B 也不自动获得该权限。
常见误用是以为友元关系可传递或继承:B 是 A 的友元,C 继承 B,不代表 C 能访问 A 的私有成员。C++ 明确不支持友元关系的继承与传递。
典型使用场景:容器与迭代器、工厂与对象构造
真正需要友元的地方,往往绕不开数据布局与接口隔离的权衡。比如标准库中 std::vector 和它的迭代器类(如 __normal_iterator)之间就存在友元关系,让迭代器能直接读取底层 _M_start、_M_finish 指针,而不暴露这些字段给所有用户。
- 容器类把迭代器声明为友元,避免为每个内部指针加 public getter(性能损耗 + 接口污染)
- 工厂类作为友元,可直接调用目标类的 private 构造函数,实现受控实例化(如单例、对象池)
- 两个紧密耦合的类(如
Node和Graph),若频繁互相访问内部状态,又不想把逻辑全塞进一个类,友元比一堆 set/get 更轻量
friend 破坏封装性的实际影响被高估了
封装性受损的前提是“本不该知道的被知道了”。但友元不是全局开放,而是点对点授权。真正的问题往往出在设计阶段:是否真的需要这种耦合?有没有更松的替代方案?
立即学习“C++免费学习笔记(深入)”;
容易踩的坑包括:
- 把友元当快捷方式滥用:本可用
public成员函数完成的操作,却用友元直接读写字段,导致后续字段重构时大量友元代码要同步改 - 友元类本身成了上帝类:一个类被十几个其他类声明为友元,说明它可能承担了太多职责,应考虑拆分
- 头文件依赖爆炸:友元声明要求友元类名可见,常迫使你在头文件里提前声明甚至包含对方头文件,增加编译依赖
替代 friend 的常见做法及其代价
不是所有“想访问私有成员”的需求都该用友元。更可控的方式包括:
- 提供精简的
public接口,比如A::get_raw_data()返回const std::vector,而非暴露原始指针& - 用
protected+ 继承:如果逻辑天然属于类族,让子类访问比让无关类访问更合理 - 借助 Pimpl 惯用法:把实现细节藏在指针后,接口类只暴露必要函数,连友元都不需要
- 使用
friend函数而非整个类:粒度更细,比如只把operator 声明为友元,而不是整个std::ostream类
友元本身不危险,危险的是跳过设计思考直接写 friend class XXX;。它解决的是“谁可以访问”,而真正的难点永远在“为什么需要这个访问”。










