C++ 友元详解:全局函数、类及成员函数的三种实现方式

陆景行
陆景行
发布时间:2026-10-15 | 4人浏览过
原创

在 C++ 面向对象编程中,为了实现某些特殊的外部访问需求(如运算符重载或特定辅助函数),我们可以利用 friend 关键字将外部函数或类声明为“友元”。本文将通过实际代码案例,讲解如何声明全局函数、类以及成员函数作为友元,以允许其直接访问目标类的私有和保护成员,同时指出定义顺序对编译结果的关键影响。

什么是 C++ 友元

C++ 的核心特性之一是封装,即隐藏内部实现细节。但在某些场景下,我们需要特定的外部实体访问类的私有成员(private)或保护成员(protected)。这可以通过 friend 关键字实现:

  • 核心目的:让指定的函数或类能够访问另一个类的私有属性,无需暴露公有接口。
  • 适用范围:友元可以是全局函数、另一个完整的类,或者是另一个类中的特定成员函数。

友元的三种实现方式

第 1 步:声明全局函数为友元

这是最基础的友元形式。只需在类内部使用 friend 关键字声明一个外部函数即可。

操作说明:

  1. 在类定义中使用 friend 关键字声明全局函数原型。
  2. 在类外部实现该函数时,可以直接访问类对象的私有成员。
class Host {
    // 声明全局函数 VisitFunc 为友元
    friend void FriendFunc(Host& H);
private:
    string m_Precious;
public:
    string m_Common;
    // 构造函数初始化
    Host() :m_Precious("五花肉粽"), m_Common("糯米粽") {}
};

// 普通函数无权限访问私有成员
void VisitNormal(Host &H) {
    cout << "普通客人只能吃到:" << H.m_Common << endl;
}

// 友元函数可以访问所有成员
void FriendFunc(Host &H) {
    cout << "好朋友可以吃到:" << H.m_Precious << "和" << H.m_Common << endl;
}

注意:建议将友元声明放在类定义的顶部或显著位置,以便清晰表明哪些外部函数拥有特权。

第 2 步:声明整个类为友元

如果希望某个类的所有成员函数都能访问目标类的私有数据,可以将该类声明为友元类。

class Host { // 东家类
    friend class FriendFunc; // 声明整个类为友元
private:
    string m_Precious;
public:
    string m_Common;
    Host() :m_Precious("五花肉粽"), m_Common("糯米粽") {}
};

class FriendFunc { // 好朋友类
public:
    Host* host;
    void visit();
    FriendFunc();
};

// 在友元类的方法中访问 Host 的私有成员
void FriendFunc::visit() {
    cout << "你的好朋友可以吃到:" << host->m_Precious 
         << "和" << host->m_Common << endl;
}

FriendFunc::FriendFunc() {
    host = new Host; // 堆区分配内存
}

void test01() {
    FriendFunc F;
    F.visit();
}

原理:友元类内部持有目标类的指针(通常通过 `new` 在堆区创建),并在其成员函数中直接操作目标类的私有数据。

第 3 步:声明成员函数为友元

有时我们只希望某个类中的特定方法具有访问权,而非全部。这需要更精确的前置声明技巧。

#include<iostream>
using namespace std;

class Host; // 前置声明,避免循环依赖编译错误

class FriendFun {
public:
    FriendFun();
    Host* host;
    void visit();   // 拥有访问权
    void visit0();  // 无访问权
};

class Host {
    // 仅指定 FriendFun 类中的 visit 方法为友元
    friend void FriendFun::visit();
private:
    string m_Precious;
public:
    string m_Common;
    Host() :m_Precious("五花肉粽"), m_Common("糯米粽") {}
};

FriendFun::FriendFun() {
    host = new Host;
}

// visit 可以访问私有成员
void FriendFun::visit() {
    cout << "特权访问:" << host->m_Precious << endl;
}

// visit0 只能访问公有成员
void FriendFun::visit0() {
    // cout << host->m_Precious; // 错误!未授权访问私有成员
    cout << "普通访问:" << host->m_Common << endl;
}

关键注意事项:定义顺序与编译逻辑

在使用类作为友元,尤其是涉及动态内存分配(`new`)时,编译器执行顺序至关重要。

  • 问题现象:如果在 FriendFun 的构造函数内部直接使用 host = new Host;,而 Host 的定义位于 FriendFun 之前但未完全展开,或者前向声明不足,编译器可能会提示“未定义类型”或无法确定对象大小。
  • 解决方案:确保目标类(Host)的完整定义在所有尝试实例化它的友元类成员函数定义之前可见。特别是在区分哪些成员函数是友元时,必须在目标类内部完成声明,且被引用的友元函数(或其类)必须已正确前向声明或定义。

总结

友元机制打破了严格的封装,需谨慎使用以避免破坏面向对象的设计原则。掌握全局函数、类和成员函数三种声明方式后,务必注意代码的书写顺序和编译器的解析过程,避免因上下文缺失导致的编译错误。以上就是C++ 友元函数与友元类用法的详细内容,更多关于C++ 访问修饰符的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表