友元函数不是类的成员,无this指针,须显式传参调用;定义时不可加类作用域限定符;不参与继承与多态;常用于重载运算符等需访问私有成员的场景。

友元函数没有 this 指针,不能通过对象调用
友元函数本质是普通函数,只是被类“授权”访问私有成员。它不隶属于任何类,因此没有隐含的 this 指针。你不能写 obj.display(),而必须写 display(obj) —— 参数得显式传入对象(或引用、指针)。
常见错误现象:把友元函数误当成成员函数,在类外定义时加 A:: 作用域限定符,比如写成 void A::display(A& a) { ... },编译器会报错:‘display’ is not a member of ‘A’。
- 友元函数定义在类外时,直接写函数名,不加类作用域
- 若形参是对象引用(推荐),访问成员需用
a.private_member,不能省略对象名 - 若形参是值传递,会触发拷贝构造;引用更高效,也避免对临时对象取地址出错
友元函数不参与继承和多态
成员函数可被继承、可被 virtual 修饰以支持运行时多态;友元函数完全游离于类的继承体系之外。哪怕基类把某个函数声明为友元,派生类对象也不能让该函数自动获得访问自己新增私有成员的权限。
使用场景:当你需要一个工具函数(如 operator、<code>Distance())能统一处理多个类,又不想每个类都重复实现,就靠友元打破封装边界——但它本身不会“随类一起演化”。
- 友元关系不继承:B 继承 A,
friend void f(A&)对 B 的对象无效 - 友元函数不能是
virtual,也不受override/final影响 - 若需多态行为,必须另设计接口(如虚函数 + 友元辅助函数组合)
友元函数声明位置不影响访问权限,但影响可见性
你在 private、protected 或 public 区域写 friend void f(A&);,效果完全一样:它始终能访问所有成员。区别只在于,如果声明在 private 区,外部代码无法通过类名查到这个友元的存在(IDE 补全、文档生成可能忽略它)。
容易踩的坑:有人以为把友元声明放在 public 下才“合法”,其实编译器根本不检查声明位置是否匹配访问需求——它只认 friend 关键字本身。
- 多个类可共享同一个友元函数,只需各自在内部加
friend声明 - 若函数尚未声明就用
friend引用,需提前声明(尤其跨类互相友元时) - 头文件中频繁使用友元易导致循环依赖,建议把实现移到 .cpp 文件
为什么不用成员函数替代?运算符重载是典型反例
当重载二元运算符且左操作数不是当前类类型时(如 int * rational),必须用非成员函数——否则 2 * r 会被解释为调用 int 类型的 operator*,而内置类型不允许重载其成员函数。
这时友元是唯一选择:它既保持了操作的对称性(r1 * r2 和 r2 * r1 都能走同一份逻辑),又能访问 rational 的私有字段(如 numerator、denominator)。
- 成员版
operator*只能处理lhs是本类对象的情形 - 非成员友元版可自由安排参数顺序,支持隐式转换(如
int → rational) - 但代价是:它绕过了封装约束,后续修改私有布局时,所有友元函数都得同步检查
友元函数不是成员函数,这件事从语法、语义到链接期都是确定的。真正容易被忽略的是:它的“特权”仅限于编译期访问检查豁免,运行时没有任何特殊待遇;一旦类的私有结构变化,所有依赖这些字段的友元函数都会悄无声息地失效——而编译器不会提醒你。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











