【C++入门】Cyber霓虹镜像城的跨域通行证 —— 【友元(friend)】跨类协作破坏封装性?友元函数与友元类为你架起特权桥梁!

⚡ CYBER_PROFILE ⚡
/// SYSTEM READY ///


WARNING : DETECTING HIGH ENERGY

🌊 🌉 🌊 心手合一 · 水到渠成

|------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------|
| >>> ACCESS TERMINAL <<< ||
| 🦾 作者主页 | 🔥 C语言核心 |
| 💾 编程百度 | 📡 代码仓库 |


Running Process: 100% | Latency: 0ms


索引与导读

友元函数

友元函数的出现缘由

  • C++的封装性将数据隐藏在类内部,但有时外部函数需要直接访问类的私有成员

    🚩友元函数解决了这一矛盾

  • 当外部函数需要频繁访问类的私有数据时,通过公有接口(getter/setter)会产生函数调用开销,友元函数可以直接访问,效率更高

  • 某些操作符(如<<>>)必须作为非成员函数重载,但又需要访问私有成员

  • 当两个或多个类需要共享数据,但这些类之间没有继承关系时,友元函数可以作为桥梁


友元函数的基本定义

cpp 复制代码
class ClassName {
private:
    // 私有成员
public:
    // 声明友元函数
    friend returnType functionName(parameters);
};

1)friend 关键字

╔═█▓▒░ CODE CORE 🔥
┌─────────────┐
friend关键字 │friend returnType functionName(parameters);
└─────────────┘

  • friend 是一个关键字,表示后面声明的是友元函数

  • 只在类内部声明时使用,在函数定义时不需要

  • 友元关系是授予的,不是索取来的

2)函数返回类型 (returnType)

cpp 复制代码
friend void functionName();           // 无返回值
friend int functionName();            // 返回int
friend MyClass functionName();        // 返回自定义类型
friend const string& functionName();  // 返回常量引用
friend auto functionName();           // C++14起可用auto

3)函数名 (functionName)

cpp 复制代码
// 可以是普通函数
friend void printData(const ClassName& obj);

// 可以是操作符函数
friend ostream& operator<<(ostream& os, const ClassName& obj);

// 可以是模板函数
template<typename T>
friend void templateFunc(T value);

4)参数列表 (parameters)

4.1)传值
cpp 复制代码
friend void func(ClassName obj);       // 传值
  • 典例
cpp 复制代码
friend void testStatus(Light light) {
    light.brightness = 100; // 仅修改副本,原灯亮度不变
}
4.2)传引用

用途: 直接修改原始对象

cpp 复制代码
friend void func(ClassName& obj);      // 传引用
  • 典例
cpp 复制代码
friend void turnOn(Light& light) {
    light.isOn = true; // 直接改变原始灯的状态
}
4.3)传常量引用

用途: 高效读取。不产生拷贝(省内存),且保证函数内部不会意外修改数据

cpp 复制代码
friend void func(const ClassName& obj);// 传常量引用
  • 典例
cpp 复制代码
friend void printInfo(const Light& light) {
    // 只能读取,尝试修改 light.isOn 会报错
    cout << "亮度: " << light.brightness << endl;
}
4.4)传指针

用途: 处理"可选"对象,可以传递 nullptr 表示没有设备

cpp 复制代码
friend void func(ClassName* obj);
  • 典例
cpp 复制代码
friend void repair(Light* light) {
    if (light) { // 检查指针是否为空
        light->isBroken = false;
    }
}
4.5)多个参数

用途: 处理两个类之间的交互

cpp 复制代码
friend void connect(ClassA& a, ClassB& b);
  • 典例
cpp 复制代码
// 在 Remote 和 Light 类中分别声明为友元
friend void pairDevice(Remote& r, Light& l) {
    r.deviceID = l.id; // 遥控器获取灯的私有 ID
    l.isPaired = true; // 灯标记为已配对
}
4.6)带默认参数

用途: 增加函数的灵活性,提供一种"常用模式",同时允许特殊配置

cpp 复制代码
friend void process(ClassName& obj, int mode = 0);
  • 典例
cpp 复制代码
friend void reset(Light& light, int level = 0) {
    light.brightness = level; // 默认调为0,也可以指定亮度
}

友元函数的特点

  • 突破封装: 允许外部访问私有成员。

  • 声明方式: 使用 friend 关键字,在类内部声明。

  • 非成员函数: 它是定义在类外部的普通函数,不属于该类,因此没有 this 指针。

  • 位置随意: 可以在类定义的任何地方声明 (public/private 区域均可)。

  • 一个函数可以是多个类的友元

cpp 复制代码
#include <iostream>
using namespace std;

class ClassB; // 【补充】:前向声明,告诉编译器 ClassB 稍后会定义

class ClassA {
private:
    int numA;
public:
    ClassA(int n) : numA(n) {}
    // 声明 friendFunction 是本类的友元
    friend int add(const ClassA& a, const ClassB& b);
};

class ClassB {
private:
    int numB;
public:
    ClassB(int n) : numB(n) {}
    // 声明同一个函数 add 也是本类的友元
    friend int add(const ClassA& a, const ClassB& b);
};

// 这个函数同时拥有访问 ClassA 和 ClassB 私有成员的权限
int add(const ClassA& a, const ClassB& b) {
    return a.numA + b.numB;
}

int main() {
    ClassA a(10);
    ClassB b(20);
    cout << "两类私有成员之和: " << add(a, b) << endl;
    return 0;
}

友元类

友元类(Friend Class)C++ 中的一种特殊机制,允许一个类访问另一个类的 私有(private)保护(protected) 成员

1)基本定义

如果一个类 A 将另一个类 B 声明为友元,那么 B 的所有成员函数都可以直接访问 A 的私有和保护成员,就好像这些成员在 B 中是公有的一样

cpp 复制代码
class A {
private:
    int private_data;

    // 声明 B 是 A 的友元类
    friend class B;
};

class B {
public:
    void func(A& obj) {
        obj.private_data = 10; // 允许访问,因为 B 是 A 的友元
    }
};

2)友元关系(友元类)的特性

  • 单向性:如果 A 是 B 的友元,这并不意味着 B 也是 A 的友元
  • 不可传递:如果 A 是 B 的友元,且 B 是 C 的友元,这并不意味着 A 是 C 的友元
cpp 复制代码
class A {
    friend class B; // B 是 A 的朋友,B 可以访问 A
private:
    int dataA;
};

class B {
    friend class C; // C 是 B 的朋友,C 可以访问 B
private:
    int dataB;
public:
    void accessA(A& a) {
        // 正确:因为 B 是 A 的友元
        a.dataA = 10; 
    }
};

class C {
public:
    void accessB(B& b) {
        // 正确:因为 C 是 B 的友元
        b.dataB = 20; 
    }

    // void accessA(A& a) {
        // 【错误】:不可传递!
        // 虽然 C -> B,B -> A,但 C 不能直接访问 A
        // a.dataA = 30; // 编译报错
    // }
};

// 同时也说明了单向性:A 并没有声明 B 是朋友,所以 A 不能访问 B 的私有成员。

💻结尾--- 核心连接协议

警告: 🌠🌠正在接入底层技术矩阵。如果你已成功破解学习中的逻辑断层,请执行以下指令序列以同步数据:🌠🌠


【📡】 建立深度链接: 关注本终端。在赛博丛林中深耕底层架构,从原始代码到进阶协议,同步见证每一次系统升级。

【⚡】 能量过载分发: 执行点赞操作。通过高带宽分发,让优质模组在信息流中高亮显示,赋予知识跨维度的传播力。

【💾】 离线缓存核心: 将本页加入收藏。把这些高频实战逻辑存入你的离线存储器,在遭遇系统崩溃或需要离线检索时,实现瞬时读取。

【💬】 协议加密解密:评论区留下你的散列码。分享你曾遭遇的代码冲突或系统漏洞(那些年踩过的坑),通过交互式编译共同绕过技术陷阱。

【🛰️】 信号频率投票: 通过投票发射你的选择。你的每一次点击都在重新定义矩阵的进化方向,决定下一个被全量拆解的技术节点。



相关推荐
阿正的梦工坊18 小时前
【Rust】07-错误处理:Option、Result 与 ? 运算符
开发语言·算法·rust
Zella折耳根18 小时前
复习篇-继承和接口
java·开发语言·python
z落落18 小时前
C# 事件(Event)+自定义带参数事件例子
开发语言·分布式·c#
FlYFlOWERANDLEAF18 小时前
DevExpress Office File API使用记录
开发语言·c#·devoffice
程序员二叉18 小时前
【JVM】OOM详解+JVM参数+FullGC排查+CPU飙高+死锁+内存泄漏+命令大全
java·开发语言·jvm·面试
云烟成雨TD18 小时前
Spring AI 1.x 系列【47】 MCP Annotations 模块
java·人工智能·spring
yijianace18 小时前
Python线程与多线程完全总结(从入门到理解并发本质)
开发语言·python
不知名的老吴18 小时前
线程的生命周期之线程同步
java·开发语言·jvm
为何创造硅基生物18 小时前
独占指针的创建std::make_unique 本身自带堆出现
c++
协享科技18 小时前
Spring Boot 与 Go 双服务架构实践:从单体拆分到通信设计
java·人工智能·spring boot·后端·架构·golang·ai编程