友元类声明必须写在被访问类的类定义体内,且仅单向授权、不继承、不传递;需前置声明被授权类,位置在public/private/protected区内均可,不影响权限。

友元类声明必须写在类定义内部
友元关系不是继承来的,也不是双向的,它只在被声明的类内部显式授权才生效。如果你把 friend class B; 写在类 A 外面,或者写在 B 的定义里,B 都无法访问 A 的私有成员。
常见错误是把友元声明放在实现文件(.cpp)里,或当成普通函数声明一样处理——这完全无效。
- 必须在
A的类体中、private或public区域内写friend class B; - 声明位置不影响访问权限,写在
public里和写在private里效果一样 - 如果
B在A之前未定义,需前置声明:class B;(在A定义前)
友元类能直接访问所有私有成员,但不获得继承权
声明为友元后,B 的成员函数可以直接读写 A 的 private 成员变量和调用 private 成员函数,不需要通过 A 的公有接口。
但这不代表 B 是 A 的子类,也不触发任何虚函数机制或访问控制链。友元不传递、不继承、不自动扩展。
-
B的任意成员函数(包括构造函数、静态函数)都能访问A实例的私有内容 - 不能通过
B的对象隐式转换成A,也不能重写A的虚函数 - 如果
A有私有嵌套类型(如private struct detail;),B可以使用它,但不能在自身作用域外公开暴露该类型
友元破坏封装性,应严格限制使用场景
友元常被误用为“绕过封装”的快捷方式,实际只适合极少数明确需要深度协作的场景,比如容器与其迭代器、PIMPL 实现、单元测试桩类。
一旦滥用,会导致类间耦合陡增,后续修改 A 的私有布局时,B 很可能静默崩溃或行为异常。
- 避免为多个类批量声明友元,尤其不要用
friend class TestSuite;这种宽泛命名 - 优先考虑将必要数据通过
const引用参数传入,或提供受控的friend函数而非整个类 - 若仅需读取,可加一层
private的get_internal_data()并将其设为friend,比开放整个类更安全
模板类的友元声明语法稍有不同
对模板类 template<typename t> class A</typename>,若想让 B 友元化所有实例,必须写成 friend class B;;若只想授权某个特化(如 A<int></int>),则要写全名。
更麻烦的是:编译器要求友元类在友元声明前已可见,而模板类定义往往很长,容易引发循环依赖。
- 正确写法:
template<typename t> class A { friend class B; };</typename>——B可访问所有A<t></t> - 若只授权
A<int></int>:friend class A<int>;</int>(注意不是friend class A;) - 模板友元函数更复杂,涉及
friend void func(A<t>&);</t>形式,容易出错,建议先验证非模板版本
friend 更可持续。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











