友元
友元允许外部函数或类访问私有成员,打破封装但方便紧密关联的类协作。
友元
友元
什么是 C++ 的友元(friend
)
在 C++ 中,类的成员通常是私有的(private)或保护的(protected),只能被该类的成员函数或其派生类访问。但是有时候,我们希望让某些“外部”函数或类也能访问这些私有成员。这就用到了 C++ 的 friend
机制。
三种常见的友元声明方式
类型 | 关键词声明方式 | 功能说明 |
---|---|---|
友元函数 | friend void foo(Class c); | 函数可以访问类的私有/保护成员 |
友元类 | friend class ClassName; | 该类的所有成员函数都能访问私有成员 |
友元成员函数 | friend void ClassB::func(); | 指定类中某个函数作为友元函数 |
示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
using namespace std;
class BankAccount {
private:
double balance;
public:
BankAccount() : balance(0.0) {}
void deposit(double amount) {
balance += amount;
}
// 声明友元函数
friend void showBalance(BankAccount acc);
// 声明友元类
friend class BankManager;
};
// 友元函数定义
void showBalance(BankAccount acc) {
cout << "Current balance: $" << acc.balance << endl;
}
// 友元类
class BankManager {
public:
void resetBalance(BankAccount& acc) {
acc.balance = 0; // 可以访问私有成员
cout << "Account reset to $0" << endl;
}
void grantBonus(BankAccount& acc, double bonus) {
acc.balance += bonus;
cout << "Granted bonus of $" << bonus << endl;
}
};
// 主函数
int main() {
BankAccount acc;
BankManager manager;
acc.deposit(100);
showBalance(acc); // ✅ 通过友元函数访问私有成员
manager.grantBonus(acc, 50); // ✅ 通过友元类访问私有成员
showBalance(acc);
manager.resetBalance(acc); // ✅ 友元类可以清空账户
showBalance(acc);
return 0;
}
友元不是继承、不是成员,而是“特许访问权限”
友元关系是单向的:A 是 B 的友元,不代表 B 是 A 的友元。
友元关系不能继承:B 是 A 的友元,B 的子类不自动拥有权限。
友元关系不破坏封装:只是给某些特定函数或类授权访问私有成员,仍然保持良好的接口设计。
友元的使用场景
使用场景 | 示例说明 |
---|---|
运算符重载需要访问私有数据 | operator+ 通常作为友元函数实现 |
工具类需要访问另一个类的内部 | BankManager |
多个类之间协作,但不想开放接口 | 如两个类之间互为友元 |
调试输出、日志等需要访问内部结构 | 如 showBalance(BankAccount) |
友元的注意事项
- 滥用友元会破坏封装性,应慎重授权。
- 友元关系是写在被访问的类中,而不是写在友元的类或函数中。
- 如果一个函数或类要做友元,需要提前声明(前置声明)。
友元函数对比成员函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Box {
int width;
public:
Box(int w) : width(w) {}
void show(); // 成员函数
friend void print(Box b); // 友元函数
};
void Box::show() {
cout << "width = " << width << endl; // ✅ 直接访问
}
void print(Box b) {
cout << "width = " << b.width << endl; // ✅ 虽是外部函数,但是友元
}
对比点 | 成员函数 | 友元函数 |
---|---|---|
是否属于类 | ✅ 是 | ❌ 不是 |
是否有 this | ✅ 有 | ❌ 没有 |
是否能访问私有成员 | ✅ 可以 | ✅ 可以(需要授权) |
调用方式 | 对象.函数() | 普通函数调用 函数(对象) |
常见用途 | 实现类的主要行为 | 运算符重载、跨类访问、调试等 |
本文由作者按照 CC BY 4.0 进行授权