友元类声明必须在被访问类定义体内的private或protected区域中,如class a { private: friend class b; };,不可写在类外或另一类中。

友元类声明写在哪?位置不对直接编译失败
友元关系不是双向的,也不是继承的,它必须在被访问类的定义体内显式声明——而且得在 private 或 protected 区域里写,不能丢到类外或函数里。
常见错误是把 friend class B; 写在类 A 定义之外,或者误以为在 B 里声明就能访问 A 的私有成员。不行。只有 A 自己说“我允许 B 碰我的私有”,B 才能碰。
- 声明必须出现在类定义内部,紧挨着访问控制符(
private:后最自然) - 被声明为友元的类
B不需要提前完整定义,前向声明class B;就够了 - 如果
B的成员函数要访问A的私有成员,那B的定义必须在A之后(否则编译器没见过B的函数体)
友元类能访问哪些成员?别高估它的权限
友元类拿到的是“进入权”,不是“上帝权”。它能直接访问目标类的所有非静态私有/保护成员,但不能绕过对象实例——也就是说,B 的成员函数里,必须通过一个具体的 A 对象(或引用、指针)去访问,不能凭空调用。
典型翻车点:在 B::func() 里写 A::private_member,报错 invalid use of non-static data member。因为这是静态访问语法,而私有成员是非静态的。
立即学习“C++免费学习笔记(深入)”;
- 必须通过对象访问:
a_obj.private_member或a_ptr->private_member - 静态私有成员可以直写
A::static_private,但非常少见,且仍需声明为 friend - 友元类不获得对目标类模板参数、友元函数嵌套逻辑的额外穿透能力
头文件循环依赖怎么破?友元让 include 更敏感
因为友元声明常牵扯两个类互相提对方名字,很容易触发头文件循环包含。比如 A.h 声明 friend class B;,而 B.h 又想包含 A.h 来用 A 的类型——这时候光靠 #pragma once 挡不住编译器报错。
根本解法是拆开声明与定义:在 A.h 用前向声明 + friend class B;;B.h 里只做前向声明;真正需要访问 A 私有成员的 B 成员函数定义,挪到 B.cpp 里,并在那里 #include "A.h"。
-
A.h:只写class B;和friend class B;,不 includeB.h -
B.h:可前向声明A,但别急着访问其私有字段 -
B.cpp:先#include "A.h",再实现那些需要碰A私有成员的函数
替代方案比友元更安全?真要跨类访问时先想想
友元破坏封装性是明确的,C++ 标准委员会都建议“仅当别无选择时使用”。很多所谓“必须友元”的场景,其实可以用更可控的方式解:比如把关键数据抽成独立结构体并设为 public,或提供受控的 get_*/set_* 接口(哪怕只给特定类用),甚至用 friend 函数代替整个类。
特别容易被忽略的一点:模板类之间无法用普通友元声明建立访问关系(除非全特化),这时硬上友元反而会卡死。不如用 make_friend 模式或策略类回调。
- 优先考虑
friend void helper(A&)而非friend class B;,粒度更细 - 若
B只读A的几个字段,不如在A里加struct View { int x; double y; } get_view() const; - 调试期临时加友元没问题,上线前务必检查是否还能收敛访问路径
友元本身没毛病,但它的存在往往意味着类边界画得不够干净——哪天你发现三个类互相 friend,那大概率该重构了。









