友元类能访问目标类私有成员但不继承该权限,声明需前置且仅单向生效,语法同普通访问,常用于容器与迭代器等必要协作场景。

友元类能访问私有成员,但不能继承访问权限
友元类不是“半个类”,它只是被授予了对目标类私有/保护成员的直接访问权,这种权限不传递、不继承、也不受派生关系影响。比如 A 声明 B 为友元,B 的子类 C 依然无法访问 A 的私有成员。
常见错误是以为在 B 中定义一个成员函数,再让 C 继承该函数就能间接访问 —— 不行,访问权限检查发生在调用点,且只看当前函数所属类是否被声明为友元。
- 友元声明必须写在类定义内部,位置不限(public/protected/private 区域都可)
- 只需声明类名,无需提前定义;但使用时(如在友元类成员函数中访问)目标类需已完整定义
-
friend class B;表示整个B类的所有成员函数都是友元,不是仅限某个函数
友元类声明要前置,否则编译报错 error: 'B' does not name a type
如果 A 在定义中声明 friend class B;,而 B 尚未声明或定义,编译器会报错。这不是语法问题,而是符号未见。
典型场景:两个类互相需要对方为友元(循环依赖),或 B 定义在 A 之后的源文件里。
- 解决方法:在
A上方加class B;前向声明(forward declaration) - 前向声明足够支持
friend class B;,但不足以支持在A内部定义调用B成员的函数 - 若需在
A中定义函数并调用B的接口,则B必须先完整定义,或把该函数实现移到类外(.cpp 文件中)
友元破坏封装性,但某些场景下不可替代
友元不是设计坏习惯的借口,而是为特定协作模式提供必要通道。最常见合理用途是:容器类与迭代器类、工厂类与被创建对象、序列化辅助类与目标数据类。
例如 std::vector 的迭代器需要直接读写其内部指针和容量,不可能靠 public 接口高效实现;又如 JSON 序列化器需读取类所有字段,包括 private 成员。
- 避免用友元绕过逻辑校验(比如直接改
balance_而不走deposit()) - 不要为图方便把业务逻辑类全设为友元,优先考虑 getter/setter 或更细粒度的友元函数
- 友元关系是单向的:
A声明B为友元,不代表B自动能访问A的友元类的私有成员
友元类中访问私有成员,和普通成员访问语法完全一致
一旦声明生效,在 B 的任意成员函数里访问 A 对象的私有成员,写法和 A 自己访问一模一样,不需要特殊语法或转换。
friend class B;
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











