友元函数用friend在类内声明但不定义,需在类外实现;无this指针,可访问私有成员;不继承,不参与ADL;声明须先于类定义,命名空间函数需带作用域。

friend声明友元函数的基本写法
friend 关键字必须出现在类定义内部,且只能修饰函数声明(不是定义),位置在类作用域中任意可访问的地方(通常放在 private 或 public 区块里)。它不改变函数本身的作用域,只是“授权”该函数访问当前类的私有和保护成员。
- 友元函数不是类的成员,因此没有
this指针,调用时需显式传入对象或引用 - 声明时函数原型可以省略参数名,但类型必须完整(如
friend void print(const MyClass&);) - 友元关系不继承:派生类不会自动获得基类友元对自身的访问权
- 友元函数可以是普通函数、其他类的成员函数,甚至函数模板特化
class MyClass {
private:
int value = 42;
public:
friend void print(const MyClass& obj); // 声明友元函数
};友元函数定义必须在类外实现
声明和定义必须分离。类内只写 friend + 函数原型;定义必须在全局或命名空间作用域中完成,且不能加 friend 关键字。
- 如果函数在类定义前未声明,编译器会报错:找不到函数声明(C++ 不允许“先使用后声明”的友元)
- 若函数属于某个命名空间,友元声明中要带完整作用域,定义时也必须在对应命名空间内
- 类内声明的友元函数不会被 ADL(参数依赖查找)自动发现,除非它已在作用域中可见
// 正确:先声明,再在类中声明为友元,最后定义
void print(const MyClass& obj);
class MyClass { /* ... friend void print(...); */ };
void print(const MyClass& obj) {
std::cout << obj.value; // OK:访问 private 成员
}常见错误:把友元当成成员函数调用
最常踩的坑是误以为友元函数能像成员函数一样通过对象点号调用,或者以为它隐式接收 this。
-
obj.print()是非法的——print不是成员,没有.调用语法 -
print(obj)才是正确调用方式 - 若函数参数是
MyClass*,仍需显式传入地址:print(&obj),不会自动取址 - 在重载操作符场景下尤其容易混淆:
friend MyClass operator+(const MyClass&, const MyClass&)必须写成a + b,不能写a.operator+(b)
友元与类外定义的成员函数混用时的陷阱
当把另一个类的成员函数声明为友元时,必须确保该成员函数在友元声明前已声明(至少是前置声明),且类名、函数签名完全匹配。
立即学习“C++免费学习笔记(深入)”;
- 需要前置声明整个类(如
class OtherClass;),再声明其成员函数原型,最后在本类中用friend引用 - 若
OtherClass定义在本类之后,而你又在本类中直接写friend void OtherClass::f();,编译器会因OtherClass未定义而报错 - 成员函数作为友元时,访问权限仅限于被授予友元的类,不反向授予——
OtherClass无法因此访问MyClass的私有成员,除非也反过来声明
友元的本质是“访问许可”,不是“关系绑定”。很多人卡在编译错误上,其实只是声明顺序或作用域没对齐,而不是语法本身有多难。


















