剖析【C++】——类和对象(下篇)——超详解——小白篇-3. 友元

友元提供了一种特殊的机制,可以让一个类允许另一个类或函数访问其私有或受保护的成员。虽然友元增加了便利性,但也会破坏封装性,增加代码耦合度,因此使用时需谨慎。

3.1 友元函数

问题描述:在重载 operator<< 时,无法将其重载为成员函数,因为 cout 作为输出流对象和 this 指针会竞争第一个参数的位置。为了使 cout 成为第一个参数,我们需要将 operator<< 重载为全局函数。但全局函数不能直接访问类的私有成员,这时就需要友元函数来解决这个问题。

友元函数的特点

  1. 可以访问类的私有和保护成员,但不属于类的成员函数。
  2. 不能用 const 修饰。
  3. 可以在类定义的任何地方声明,不受类访问限定符限制。
  4. 一个函数可以是多个类的友元函数。
  5. 友元函数的调用与普通函数的调用相同。

示例代码

#include <iostream>
using namespace std;

class MyClass {
private:
    int value;

public:
    MyClass(int v) : value(v) {}

    // 声明友元函数
    friend ostream& operator<<(ostream& os, const MyClass& obj);
};

// 定义友元函数
ostream& operator<<(ostream& os, const MyClass& obj) {
    os << obj.value;
    return os;
}

int main() {
    MyClass obj(42);
    cout << obj << endl;  // 输出: 42
    return 0;
}

在上面的代码中,operator<< 被定义为友元函数,因此它可以访问 MyClass 类的私有成员 value

3.2 友元类

友元类是一种类的所有成员函数都可以访问另一个类的私有和保护成员的机制。

特点

  1. 友元关系是单向的,不具有交换性。例如,如果 A 类是 B 类的友元,那么 B 类可以访问 A 类的私有成员,但反过来 A 类不能访问 B 类的私有成员。
  2. 友元关系不能传递。如果 BA 的友元,而 CB 的友元,这并不意味着 CA 的友元。
  3. 友元关系不能继承。

示例代码

#include <iostream>
using namespace std;

class Date;

class Time {
private:
    int hour;
    int minute;

public:
    Time(int h, int m) : hour(h), minute(m) {}

    // 声明Date类为友元类
    friend class Date;
};

class Date {
private:
    int day;
    int month;
    int year;

public:
    Date(int d, int m, int y) : day(d), month(m), year(y) {}

    void displayTime(const Time& t) {
        // 访问Time类的私有成员
        cout << "Time: " << t.hour << ":" << t.minute << endl;
    }
};

int main() {
    Time t(10, 30);
    Date d(1, 5, 2023);
    d.displayTime(t);  // 输出: Time: 10:30
    return 0;
}

在上面的代码中,Date 类被声明为 Time 类的友元类,因此 Date 类的成员函数可以访问 Time 类的私有成员。

3.3总结

  • 友元函数和友元类允许访问私有和保护成员,但要谨慎使用,因为这会增加代码的耦合性。
  • 友元关系是单向的,不可传递。
  • 使用友元可以解决一些特殊情况下的访问权限问题,如重载运算符等。

上一篇:Docker基础篇之Docker入门介绍


下一篇:算法(七)插入排序