友元函數**不是類的成員函數**,但可訪問類的 `private`/`protected` 成員。
聲明在類內 (加 `friend` 關鍵字),定義在類外 (**不加** `friend`),像普通全局函數一樣定義。
#ifndef MYCLASS_H
#define MYCLASS_H
#include
class MyClass {
private:
int secretData;
std::string name;
public:
MyClass(int data, const std::string& n) : secretData(data), name(n) {}
// 1. 友元函數聲明 (僅聲明,加 friend)
friend void printSecret(const MyClass& obj); // 普通全局函數
friend std::ostream& operator<<(std::ostream& os, const MyClass& obj); // 運算符重載
friend void modifyData(MyClass& obj, int newVal); // 可修改私有成員
};
#endif
#include "MyClass.h"
#include
// 2. 友元函數定義 (類外,不加 friend,像普通函數)
void printSecret(const MyClass& obj) {
// 可直接訪問 private 成員
std::cout << "Object [" << obj.name << "] Secret: " << obj.secretData << std::endl;
}
// 運算符重載友元
std::ostream& operator<<(std::ostream& os, const MyClass& obj) {
os << "MyClass{name='" << obj.name << "', secret=" << obj.secretData << "}";
return os;
}
void modifyData(MyClass& obj, int newVal) {
obj.secretData = newVal; // 修改私有成員
}
#include "MyClass.h"
#include
int main() {
MyClass obj(42, "TestObject");
// 調用友元函數
printSecret(obj); // 輸出: Object [TestObject] Secret: 42
// 使用運算符重載
std::cout << obj << std::endl; // 輸出: MyClass{name='TestObject', secret=42}
// 修改私有數據
modifyData(obj, 100);
printSecret(obj); // 輸出: Object [TestObject] Secret: 100
return 0;
}
| 項目 | 規則 |
|---|---|
| 聲明位置 | 類定義內部,`friend` 關鍵字開頭 |
| 定義位置 | 類定義外部 (通常在 .cpp 文件),**不加** `friend` |
| 訪問權限 | 可訪問 `private`、`protected` 非靜態成員 (需對象實例)、靜態成員 (直接類名::) |
| this 指針 | **無** `this` 指針,必須顯式傳遞對象引用/指針參數 |
| 作用域 | 全局/命名空間作用域,非類作用域 |
| 聲明重複 | 可在多個類中聲明同一函數為友元 (如運算符重載常聲明為兩個類的友元) |
class FriendClass {
public:
void accessMyClass(MyClass& obj) {
obj.secretData = 999; // 友元類的所有成員函數均可訪問
}
};
class MyClass {
friend class FriendClass; // 整個類聲明為友元
// ...
};
友元函數:**類內 `friend` 聲明,類外普通定義**。本質是打破封裝的「特權訪問者」,慎用、精用,主要服務於運算符重載與極少數緊密耦合場景。