%% # 纲要 > 主干纲要、Hint/线索/路标 # Q&A #### 已明确 #### 待明确 > 当下仍存有的疑惑 **❓<font color="#c0504d"> 有什么问题?</font>** %% # 类的友元 **友元(Friend)** 是 **一个类允许==其它"非成员函数"或"其它类"==访问其 `private` 和 `protected` 成员的机制。** 友元通过在**类定义内部**使用 `friend` 关键字声明,可以是下列三种: - **友元函数**:将一个类外的**普通非成员函数**声明为友元(要求**该函数不能被 `static` 修饰**); - **友元类**:将一个其它类声明为友元; - **友元成员函数**:将其它类的一个特定成员函数声明为友元; > [!NOTE] 友元声明不受类的访问说明符影响,可以放在任何位置。 友元关系的性质: - **友元关系是==单向的**==:即如果类 A 声明了类 B 为友元,则类 B 可以访问类 A 的私有和保护成员,但类 A 不能访问类 B 的私有和保护成员,除非类 B 也声明类 A 为友元。 - **友元关系==不具有传递性==:** A 是 B 的友元,B 是 C 的友元,并不意味着 A 是 C 的友元; - **友元关系==不具有继承性**==:**基类的友元并不意味着是派生类的友元**,反之亦然。 > [!caution] `static` 修饰的函数不能作为类的 "友元函数"! > > **友元声明**" 的函数本身需要在类外有明确定义,**具有外部链接性**,与 `static` 限制为内部链接性的机制冲突。 > 即使该 `static` 函数就定义于类定义所在的编译单元上下文中,也不可行,如下所示: > > ![[_attachment/02-开发笔记/01-cpp/类与对象/cpp-类的友元.assets/IMG-cpp-类的友元-DE18F268D111FF6F23DC1AB0D1BBEDFE.png|699]] > > ![[_attachment/02-开发笔记/01-cpp/类与对象/cpp-类的友元.assets/IMG-cpp-类的友元-A9291818839BA946FBA6744BA3E62F3D.png|703]] > > > 示例一:声明友元 ```cpp class MyClass { int data; public: MyClass(int value) : data(value) {} // 声明友元 friend void friendFunction(MyClass &obj); // 声明友元函数 friend class FriendClass; // 声明友元函数 friend void OtherClass::firendMemberFunc(MyClass &obj); // 声明友元成员函数 }; // 友元函数: 友元函数内可以访问MyClass的私有成员 void friendFunction(MyClass &obj) { std::cout << obj.data; // } // 友元类: 类的所有成员函数都可以访问另一个类的私有和保护成员。 class FriendClass { public: void accessMyClass(MyClass &obj) { std::cout << obj.data; } }; // 友元成员函数: 另一个类中的某个特定成员函数被允许访问当前类的私有和保护成员. class OtherClass { public: void friendMemberFunction(MyClass &obj) { std::cout << obj.data; } }; ``` <br><br> # 友元声明注意事项 🚨 "友元声明" `friend` 只能出现在 "**类定义内部**",其唯一作用是 "**标识一个==非成员函数或类中可访问当前类的`protected` 与 `private` 成员==**", **并不等同于 "对该非成员函数或类进行 "函数声明" 或 "类的前置声明"**,其假定该友元名字 "**在当前作用域可见**"。 > [!caution] 即使在声明 `friend` 的同时,**直接在==类内==对该友元函数进行了定义**,该**友元函数仍是 "==未声明==" 的**。 > [!NOTE] 使用建议 > > - 如果要**在==类的成员函数==中使用该友元函数**,必须**确保 "该友元" ==本身的声明或定义==在 "类成员函数" 定义之前可见**! > - 参见 "示例一/二" > - 如果要**让类的用户能够调用友元函数**,应当**在类声明之外独立地对所有友元进行一次声明**。 > - 参见 "示例三" > 示例一: ```cpp class X { friend void f() { ... } // 友元函数可以定义在类的内部, 但同样是 "未声明的" // X() { f(); } // 错误: f还没有被声明(即使直接在类内部定义了友元函数, 仍是未声明的) void h(); } // void X:h() { return f(); } // 错误: f还没有被声明 void f(); // 声明f void X::h() { return f(); } // 正确: 现在f的声明在作用域中了 ``` 示例二: ```cpp void f() {} struct X { friend void f(); void g() { f(); // 正确, `f()`已声明过, 是可见的. } }; ``` 示例三:类定义之外最好也独立地声明友元 ```cpp // MyClass.h class MyClass { int data; public: MyClass(int value) : data(value) {} // 声明友元(仅声明了访问权限) friend void friendFunction(MyClass &obj); // 声明友元函数 friend class FriendClass; // 声明友元函数 friend void OtherClass::firendMemberFunc(MyClass &obj); // 声明友元成员函数 }; // 类定义之外独立地声明友元 void friendFunction(MyClass &obj); class FriendClass; // 前向声明 void OtherClass::friendMemberFunct(Myclass &obj); ``` <br><br> # Buffer ## 闪念 > sudden idea ## 候选资料 > Read it later # ♾️参考资料 # Footnotes