文章

友元

友元允许外部函数或类访问私有成员,打破封装但方便紧密关联的类协作。

友元

友元

什么是 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. 如果一个函数或类要做友元,需要提前声明(前置声明)。

友元函数对比成员函数

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 进行授权