友元类声明必须写在被访问类内部,且仅由该类单方面授予;常见错误包括声明位置错误、拼写不一致、前置声明不足;友元关系不传递、不继承,不受访问限定符影响,且易引发循环依赖问题。

友元类声明必须写在类内部
友元关系不是继承来的,也不是双向的,它只由被访问类单方面授予。想让 ClassB 访问 ClassA 的私有成员,必须在 ClassA 定义体内用 friend class ClassB; 明确声明——放在 private、protected 或 public 区域都行,但必须是类定义的一部分。
常见错误是把 friend 声明写在类外,比如在实现文件里补一句 friend class ClassB;,这完全无效,编译器直接忽略。
- 声明位置错误:写在类定义之外 → 编译不报错但无效果
- 拼写不一致:比如
friend class classB;(大小写)或friend struct ClassB;(用了struct但实际是class)→ 友元关系不成立 - 前置声明不足:若
ClassB在ClassA前未声明,需先加class ClassB;前置声明
友元类能直接访问所有私有/保护成员
一旦声明生效,ClassB 的任何成员函数(包括构造、析构、静态函数)都能像访问自己成员一样读写 ClassA 的 private 和 protected 成员,无需通过 public 接口。
例如:
立即学习“C++免费学习笔记(深入)”;
class A {
private:
int x = 42;
void secret() { }
friend class B; // 关键声明
};
class B {
public:
void f(A& a) {
a.x = 100; // ✅ 合法:直接修改私有成员
a.secret(); // ✅ 合法:直接调用私有函数
}
};
注意:B 的友元权限仅限于访问 A 的实例,不能绕过访问控制去操作其他类的私有成员,也不能把这种权限“转授”给 B 的友元。
友元不传递、不继承,也不受访问限定符影响
友元关系严格遵循“谁声明、谁授权、谁可用”的原则。即使 B 是 A 的友元,B 的子类 C 依然无法访问 A 的私有成员;同样,B 的友元类 D 也拿不到这个权限。
-
class C : public B {};→C::g(A& a) { a.x = 0; }会编译失败 -
friend class D;在B里声明 →D仍不能访问A的私有成员 - 把
friend class B;放在A的private区域 → 效果和放在public一样,friend本身不受访问控制修饰
头文件循环依赖时友元声明容易失效
当 A.h 和 B.h 相互包含,又在各自类里声明对方为友元,编译器可能因未完成类型而拒绝友元声明。典型报错:'B' is incomplete 或友元不生效。
解决方式是拆解依赖:
- 在
A.h中只做class B;前置声明,把friend class B;放进去 - 把
A的完整定义(含友元声明)和B的完整定义,都移到实现文件(如A.cpp)中,并确保#include "B.h"在友元使用前 - 更稳妥的做法:避免双向友元,改用
public的访问器函数,或重新设计接口边界
友元是破坏封装的显式许可,用得越少,后期维护时越不容易踩到隐式耦合的坑。


















