Bootstrap

[C++]友元函数和友元类

1. 友元函数

1.1 友元函数的概念

友元函数是一个非成员函数,它被类声明为“友元”,从而能够访问类的私有成员和保护成员。正常情况下,类的外部函数是不能访问类的私有成员的,而友元函数打破了这一限制。

class MyClass {
private:
    int x;
public:
    MyClass() : x(10) {}
    friend void showX(MyClass obj); // 友元函数声明
};

// 友元函数定义
void showX(MyClass obj) {
    cout << "The value of x: " << obj.x << endl; // 访问私有成员
}

1.2 大白话解释为什么

类的私有成员本来是为了保护数据不被外部随意访问,确保类的封装性。然而,有时我们确实需要让外部的非成员函数访问类的私有数据(例如做一些特定操作或性能优化)。这时,我们通过friend关键字声明友元函数,让它“破例”访问类的私有成员,但这种访问是有限制的——友元函数不属于类,不能直接访问类的其他成员。

1.3 实际使用

1.3.1示例:友元函数访问私有数据

#include <iostream>
using namespace std;

class Box {
private:
    int width;
public:
    Box(int w) : width(w) {} // 构造函数

    // 友元函数声明
    friend void printWidth(Box box);
};

// 友元函数定义
void printWidth(Box box) {
    cout << "Box width: " << box.width << endl; // 直接访问私有成员
}

int main() {
    Box box(10);
    printWidth(box); // 通过友元函数访问私有成员
    return 0;
}

1.3.2代码解释:

  • Box类中有一个私有成员width,普通的成员函数不能直接访问它。
  • 通过friend关键字,printWidth函数成为了Box类的友元函数,它可以访问Box类的私有成员width
  • 这段代码的执行结果会输出Box width: 10,显示width的值。

1.3.3注意事项:

  • 友元函数并不属于类,类外的普通函数通过friend关键字可以访问类的私有数据,但它并不能访问类的成员函数或其他私有成员。
  • 友元函数的访问权限仅限于类的私有和保护成员。
  • 友元函数在类内声明,在类外定义。

2. 友元类

2.1 友元类的概念

友元类是指一个类允许另一个类访问它的私有成员。通过friend关键字,我们可以让一个类成为另一个类的友元类,从而让这个类的所有成员函数访问另一个类的私有成员。

class Car; // 提前声明类

class Engine {
public:
    void showCarSpeed(Car& car); // 成员函数,访问Car的私有数据
};

class Car {
private:
    int speed;
public:
    Car(int s) : speed(s) {} // 构造函数

    // 声明Engine为友元类
    friend class Engine; // Engine是Car的友元类
};

// Engine类的成员函数可以访问Car的私有成员
void Engine::showCarSpeed(Car& car) {
    cout << "Car speed: " << car.speed << endl; // 直接访问Car的私有成员
}

int main() {
    Car car(100);
    Engine engine;
    engine.showCarSpeed(car); // Engine通过友元关系访问Car的私有成员
    return 0;
}

2.2 大白话解释为什么

有时候两个类之间的功能紧密相关,需要彼此直接访问对方的私有数据。直接暴露所有的私有成员可能破坏封装性,但通过友元类,可以让一个类“授权”另一个类访问它的私有成员,而不暴露给外界。这让两个类能够协同工作,同时又不破坏类的封装性。

2.3 实际使用

2.3.1示例:友元类之间的合作

#include <iostream>
using namespace std;

class Engine; // 提前声明

class Car {
private:
    int speed;
public:
    Car(int s) : speed(s) {}

    // 声明Engine类为友元类
    friend class Engine; // Engine可以访问Car的私有成员
};

class Engine {
public:
    void showCarSpeed(Car car) {
        cout << "Car speed: " << car.speed << endl; // 访问Car类的私有成员
    }
};

int main() {
    Car car(120);
    Engine engine;
    engine.showCarSpeed(car); // Engine访问Car的私有成员
    return 0;
}

2.3.1代码解释:

  • Car类包含一个私有成员speed,我们希望Engine类能够访问它。
  • 通过friend class Engine;,我们让Engine类成为Car类的友元类,因此Engine类的成员函数能够直接访问Car的私有成员speed
  • main函数中,创建了一个Car对象,并通过Engine类访问其私有成员。

2.3.3注意事项:

  • 友元类能够访问被声明为友元的类的所有私有成员。
  • 友元类不是继承关系,它只是被授权访问类的私有数据,因此它不具有类之间的继承功能。
  • 如果多个类需要访问彼此的私有成员,可以将它们互相声明为友元类。
  • 友元类也是在类内声明,在类外定义。

3. 总结

3.1 友元函数总结

  • 友元函数是非成员函数,但被允许访问类的私有成员。
  • 通过friend关键字声明友元函数,它可以访问类的私有数据。
  • 友元函数并不是类的成员,它只能访问类的私有和保护成员,而不能访问类的其他成员函数或成员变量。
  • 友元函数的访问权限仅限于该类的私有和保护成员。

3.2 友元类总结

  • 友元类是允许访问另一个类私有成员的类。
  • 通过friend class关键字声明友元类,使得友元类的成员函数能够访问被声明类的私有数据。
  • 友元类和继承关系不同,它只是授权给一个类访问另一个类的私有成员,不会影响类的继承关系。
  • 友元类是双向授权的,即一个类可以将另一个类声明为友元类,反之亦然。
;