友元函数不是类的成员但可访问私有/保护成员,声明必须在类内用friend关键字(不加访问修饰符和const等,需分号),定义在类外;参数至少一个为本类类型(推荐const&),用于运算符重载等场景。

友元函数不是类的成员,但它能访问类的私有和保护成员——关键在于 friend 关键字必须出现在类内部的声明中,且仅声明,不定义;定义必须在类外,像普通函数一样。
友元函数声明必须写在类内部,且不能带 public/private
很多人误以为 friend 函数可以像成员函数那样放在 public 区域里,或者加 const 修饰。其实:friend 声明本身不受访问控制符影响,它只是“授权”,不是“归属”。
-
friend声明只能出现在类定义内部,位置任意(public、private或protected区都可,但推荐统一放在顶部或底部) - 声明时不能加
public、static、virtual、const等修饰符 - 声明末尾必须有分号,这是易漏点
- 函数定义必须在类外,且不能用
::作用域解析符(因为它不是成员)
友元函数参数至少有一个是当前类类型(或引用/指针)
否则编译器无法建立“访问授权”的上下文关系。常见错误是把友元函数写成无参函数,或只传基本类型,这时即使加了 friend,也无法访问私有成员。
- 典型签名:
friend void print(const MyClass& obj);或friend bool operator==(const MyClass& a, const MyClass& b); - 若参数全是
int、std::string等非本类类型,该函数根本不会获得访问权限 - 传值、传引用、传指针均可,但推荐传
const&避免拷贝和意外修改
友元破坏封装性,但重载运算符时几乎无法避免
很多人想用友元实现 或 ==,却忘了左操作数是标准类型(如 std::ostream),没法把 operator 写成 ostream 的成员函数——这时友元是唯一合规解法。
立即学习“C++免费学习笔记(深入)”;
operator 必须是友元(或类内定义为成员,但那样std::cout 就变成obj ,语义错乱)- 二元运算符如
+、==、若需左操作数为非本类对象(比如5 + obj),也得靠友元支持隐式转换场景 - 友元不继承:基类的友元对派生类私有成员无访问权
- 友元不传递:A 是 B 的友元,B 是 C 的友元,不代表 A 能访问 C 的私有成员
class Box {
private:
double width;
double height;
public:
Box(double w = 1.0, double h = 1.0) : width(w), height(h) {}
// 友元声明:注意分号,不加 public,不加 const
friend void printWidth(const Box& box);
friend Box operator+(const Box& a, const Box& b);
};
// 类外定义:不加 friend,不加 Box::,就是普通函数
void printWidth(const Box& box) {
std::cout << "Width: " << box.width << std::endl; // OK:访问私有成员
}
Box operator+(const Box& a, const Box& b) {
return Box(a.width + b.width, a.height + b.height); // OK
}
最容易被忽略的是:友元函数的声明和定义必须类型完全一致(包括 const、引用、模板特化),否则链接时报 “undefined reference”。尤其在头文件中声明、源文件中定义时,拼写或 const 修饰不一致,问题极难排查。









