当前位置: 首页 > news >正文

C++中的友元 之七

很好 👍
你这个问题已经不是“语法层面”了,而是:

friend 在 C++ 进化史中扮演了什么角色?
它有没有被削弱?加强?替代?规范化?

我们按时间线 + 设计演化来讲。你会看到一个非常清晰的脉络。


一、先说一个结论(很重要)

friend 从 C++98 到 C++23:

  • ❌ 没被废弃
  • ❌ 没被削弱
  • ✅ 被“规范化使用”
  • ✅ 在模板与模块时代变得更精细

也就是说:

它不是历史遗留问题
而是核心语言机制


二、C++98 时代:friend 的原始形态

最初的 friend 很简单:

class A {friend void f(A&);
};

作用:

  • 编译期授权
  • 无运行期开销
  • 纯语法机制

这个阶段的特点:

  • 模板支持不完善
  • 没有 move 语义
  • 没有 auto
  • 没有模块

friend 只是一个访问控制工具。


三、C++11:模板时代的 friend 爆发

这是第一次重大进化。

1️⃣ 模板友元

你可以写:

template<typename T>
class A {friend T;
};

这意味着:

任意类型 T 都可以成为 friend

这是泛型编程的关键能力。


2️⃣ 更常见的模板友元函数

template<typename T>
class Box {friend void Print<>(const Box<T>&);
};

注意这个 <>

它的意思是:

这个 friend 是某个函数模板的实例

C++11 之后,模板 + friend 的交互规则被大幅明确。

否则泛型库根本无法实现。


四、C++11 之后:与移动语义的配合

移动语义出现后:

  • move constructor
  • move assignment

很多实现需要访问 private 成员。

例如:

class Buffer {friend void swap(Buffer&, Buffer&) noexcept;
};

swap 通常写成 friend。

为什么?

因为:

  • 需要直接交换内部指针
  • 要求极致性能
  • 不希望暴露内部结构

自从 C++11 起:

friend 成为“高性能值语义设计”的常规工具


五、C++17:更干净的 friend 模式

C++17 强调:

inline friend

例如:

class Complex {
public:Complex(double r, double i) : r(r), i(i) {}friend Complex operator+(Complex lhs, const Complex& rhs){lhs.r += rhs.r;lhs.i += rhs.i;return lhs;}private:double r, i;
};

这是 C++17 以后非常流行的写法。

特点:

  • 函数定义直接写在类内
  • 但它不是成员函数
  • 它是 inline 非成员函数
  • 参与 ADL

这是一种非常优雅的写法。


六、C++20:模块(Modules)时代的变化

C++20 引入模块。

这是友元真正“升级”的地方。

在传统头文件时代:

friend 是文件级可见。

但模块时代:

friend 可以:

  • 仅在模块内部可见
  • 不暴露给外部用户

例如:

export module math;export class Matrix {friend class MatrixOperator; // 仅模块内可见
};

外部用户:

  • 看不到 MatrixOperator
  • 但模块内部可以访问 private

这让 friend 真正成为:

模块内部信任机制

而不是“全局污染机制”。


七、C++20:概念(Concepts)与 friend

在 Concepts 时代:

friend 可以配合约束模板。

例如:

template<typename T>
concept Printable = requires(T t) {std::cout << t;
};class A {template<Printable T>friend void Print(const T&);
};

这让 friend 的授权更精确。

以前是:

给某个函数

现在可以:

给满足某个概念的函数模板


八、C++23:没有削弱 friend,反而依赖它

现代标准库实现中:

  • ranges
  • views
  • coroutine
  • allocator

内部大量使用 friend。

因为:

现代 C++ 强调:

强封装 + 高性能 + 零开销

friend 正好满足:

  • 不暴露实现
  • 允许内部算法直接操作

九、真正的演化方向

你可能以为:

“现代语言都在减少 friend 这种破坏封装的机制”

其实恰恰相反。

现代 C++ 的方向是:

把 friend 从“随便用的工具”
变成“模块内部的精细授权工具”


十、和 C# 的演化对比

C# 的方向:

  • internal
  • partial
  • assembly
  • reflection

C++ 的方向:

  • friend
  • 模块
  • ADL
  • inline 非成员函数

C# 通过程序集控制边界。

C++ 通过 friend + module 控制边界。


十一、现代 C++ 中 friend 的最佳实践

现在的共识是:

1️⃣ 优先普通非成员函数
2️⃣ 如果需要 private,使用 friend
3️⃣ friend 应该局限在同一逻辑模块
4️⃣ 尽量 inline 定义
5️⃣ 不要跨模块滥用


十二、你真正应该惊讶的点

friend 在 C++ 里从未被视为“坏设计”。

它是:

为了实现“零成本抽象”必须存在的机制

因为:

如果没有 friend,

标准库几乎无法实现现在的性能水平。


十三、真正高级的视角

在现代 C++ 中:

friend 不是“破坏封装”。

而是:

定义一个抽象内部的信任域

一个抽象可能由:

  • 多个类
  • 多个函数模板
  • 多个辅助类型

组成。

friend 让这些内部组件可以协作。


十四、总结时间线

版本 friend 的角色
C++98 访问控制工具
C++11 模板友元成熟
C++17 inline friend 流行
C++20 模块内部信任机制
C++23 与 ranges / 泛型深度结合

十五、你现在应该建立的认知

friend 不是:

❌ 语法怪物
❌ 遗留设计
❌ 反面教材

它是:

✅ 泛型编程的基石
✅ 值语义设计的核心工具
✅ 模块封装的内部桥梁


http://www.jsqmd.com/news/415516/

相关文章:

  • CT断层成像系列10——三维锥束FDK重建算法(附Matlab代码)
  • 东方博宜OJ 1108:正整数N转换成一个二进制数 ← 字符串 / 栈
  • 渗透测试零基础入门!从环境搭建到实战靶场通关,一篇吃透
  • 【渗透测试】一文吃透SQL注入漏洞!原理+分类+实战利用+防御方案
  • 260204
  • 【Playwright 】端到端自动化的开源框架
  • 【matlab】GUI句柄
  • 专业的文件上传漏洞检测工具,支持263+绕过技术、代理抓包、动态扫描
  • C++中的友元 之六
  • 五款免费AI视频生成神器,效果炸裂!
  • STM32F103C8T6 驱动 180° 舵机(SG90)超详细教程
  • 【开题答辩全过程】以 共享单车使用情况预测模型的设计与实现为例,包含答辩的问题和答案
  • C++中的友元 之五
  • 互斥锁
  • 数据库的应用-第一天
  • P3035 [USACO11DEC] Umbrellas for Cows S 题解
  • AI Compose Commit:用 AI 智能重构 Git 提交工作流
  • 题解:P11567 建造军营 II
  • C++中的友元 之四
  • 哈萨克斯坦旅游出行笔记
  • 2026年广州名士表手表维修推荐榜单评测:非官方维修网点服务与售后中心选择指南 - 十大品牌推荐
  • Gin 框架中的规范响应格式设计与实现
  • Computer Vision (Prof. Andreas Geiger, University of Tbingen)
  • QOJ #7324. Eulerian Orientation 题解
  • 2026年广州摩凡陀手表维修推荐榜单:非官方维修网点服务评测与选择指南 - 十大品牌推荐
  • 本次AIGC论文助手精心整理并发布了十大高效AI写作工具的详细专业测评分析
  • 最可爱の树剖姐姐
  • 距国自然申报仅剩20天!您确定自己的本子“读懂“2026新规了吗?
  • C++中的友元 之三
  • C++中的友元 之二