0

0

c++的friend声明有哪些合理的用例? (单元测试与序列化)

裘德小鎮的故事

裘德小鎮的故事

发布时间:2026-01-13 13:29:22

|

519人浏览过

|

来源于php中文网

原创

friend 是C++中可控破例机制,用于单元测试和序列化时安全访问私有成员;不应滥用作跨模块接口,且需注意ODR、ADL及PIMPL等场景的编译与ABI风险。

c++的friend声明有哪些合理的用例? (单元测试与序列化)

friend 用于单元测试时绕过私有访问限制

当类的私有成员(如内部状态、缓存字段、未公开的辅助函数)需要被测试验证,但又不应暴露为 public 或 protected 时,friend 是最轻量的可控破例方式。它比把测试类塞进继承体系更干净,也比把所有待测成员设为 public 更安全。

常见错误是直接将整个测试类声明为 friend,导致耦合过重;更合理的做法是只 friend 具体的测试函数(C++11 起支持),或用匿名命名空间内的自由函数。

  • 测试函数必须在类定义前已声明,否则编译器不识别
  • 若测试代码在 .cpp 文件中,需确保该函数声明在头文件中可见(通常放在类定义下方、同一头文件内)
  • Clang 和 GCC 对 friend 函数的 ODR(One Definition Rule)检查较严格,避免在多个 TU 中重复定义 friend 函数体
class BankAccount {
private:
    double balance_ = 0.0;
    int transaction_count_ = 0;

    void log_transaction() { ++transaction_count_; }

    // 只允许特定测试函数访问
    friend void test_balance_and_count();
};

friend 用于序列化/反序列化逻辑解耦

当使用非侵入式序列化库(如 boost::serializationcereal)时,friend 是标准推荐方案:它让序列化函数能直接读写私有成员,同时不破坏封装边界——序列化逻辑本身不在类内部,也不依赖 public 接口模拟数据结构。

关键点在于:序列化函数不是类的接口,而是外部协议适配层。把它设为 friend,语义上清晰表达了“此函数获准以实现为目的访问内部表示”,而非“此函数是类的一部分”。

立即学习C++免费学习笔记(深入)”;

Rationale
Rationale

Rationale 是一款可帮助企业主、经理和个人做出艰难的决定的AI工具

下载
  • boost::serialization 要求 serialize 成员函数为 template 并声明为 friend,否则无法访问私有字段
  • 使用 cereal 时,CEREAL_CLASS_VERSION 不需要 friend,但自定义 save/load 函数若访问私有成员,则必须 friend
  • 注意 ADL(Argument-Dependent Lookup):某些序列化库依赖友元函数参与查找,若忘记 friend,可能静默调用默认泛型版本,导致序列化内容为空或崩溃
class Config {
private:
    std::string api_key_;
    int timeout_ms_;

    friend class cereal::access;
    template
    void serialize(Archive& ar) {
        ar(CEREAL_NVP(api_key_), CEREAL_NVP(timeout_ms_));
    }
};

friend 不该用于跨模块接口或替代设计重构

有人用 friend 让另一个业务类(比如 LoggerValidator)直接读写本类私有成员,这本质上是把封装契约交给了编译期信任,而非运行时契约。一旦 friend 类变更内部逻辑,原类就可能静默失效。

真正合理的替代路径通常是:提取观察者接口(如 get_debug_state())、引入回调机制、或用 visitor 模式。只有当性能压倒一切(如高频日志中避免 getter 拷贝)且 friend 类与本类生命周期/演进强绑定时,才考虑此用法。

  • friend 声明不能出现在类模板特化之外的局部作用域,也不能在函数体内
  • friend 关系不可继承:基类的 friend 不能访问派生类新增的私有成员
  • 多个 friend 声明不会自动聚合权限;每个都必须显式写出

容易被忽略的链接与 ABI 风险

friend 函数的符号名会进入类所在命名空间的关联集(associated namespaces),影响 ADL 行为。更隐蔽的问题是:如果 friend 函数定义在头文件中且含内联实现,而它又调用了类的私有构造/析构,那么不同编译单元对私有成员的访问布局理解必须一致——这在开启不同优化等级或混用 STL 实现时可能出问题。

尤其要注意 PIMPL 惯用法下 friend 的使用:若 friend 函数直接操作 pimpl_ 指针所指对象的私有成员,而该对象定义在 .cpp 中,头文件里只有前向声明,此时 friend 声明本身合法,但函数定义处若尝试访问其私有成员,就会编译失败。

相关专题

更多
treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

533

2023.12.01

C++ 高效算法与数据结构
C++ 高效算法与数据结构

本专题讲解 C++ 中常用算法与数据结构的实现与优化,涵盖排序算法(快速排序、归并排序)、查找算法、图算法、动态规划、贪心算法等,并结合实际案例分析如何选择最优算法来提高程序效率。通过深入理解数据结构(链表、树、堆、哈希表等),帮助开发者提升 在复杂应用中的算法设计与性能优化能力。

17

2025.12.22

深入理解算法:高效算法与数据结构专题
深入理解算法:高效算法与数据结构专题

本专题专注于算法与数据结构的核心概念,适合想深入理解并提升编程能力的开发者。专题内容包括常见数据结构的实现与应用,如数组、链表、栈、队列、哈希表、树、图等;以及高效的排序算法、搜索算法、动态规划等经典算法。通过详细的讲解与复杂度分析,帮助开发者不仅能熟练运用这些基础知识,还能在实际编程中优化性能,提高代码的执行效率。本专题适合准备面试的开发者,也适合希望提高算法思维的编程爱好者。

13

2026.01.06

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1015

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

62

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

381

2025.12.29

PHP 表单处理与文件上传安全实战
PHP 表单处理与文件上传安全实战

本专题聚焦 PHP 在表单处理与文件上传场景中的实战与安全问题,系统讲解表单数据获取与校验、XSS 与 CSRF 防护、文件类型与大小限制、上传目录安全配置、恶意文件识别以及常见安全漏洞的防范策略。通过贴近真实业务的案例,帮助学习者掌握 安全、规范地处理用户输入与文件上传的完整开发流程。

2

2026.01.13

PPT交互图表教程大全
PPT交互图表教程大全

本专题整合了PPT交互图表相关教程汇总,阅读专题下面的文章了解更多详细内容。

47

2026.01.12

Java 项目构建与依赖管理(Maven / Gradle)
Java 项目构建与依赖管理(Maven / Gradle)

本专题系统讲解 Java 项目构建与依赖管理的完整体系,重点覆盖 Maven 与 Gradle 的核心概念、项目生命周期、依赖冲突解决、多模块项目管理、构建加速与版本发布规范。通过真实项目结构示例,帮助学习者掌握 从零搭建、维护到发布 Java 工程的标准化流程,提升在实际团队开发中的工程能力与协作效率。

19

2026.01.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
SQL 教程
SQL 教程

共61课时 | 3.4万人学习

C# 教程
C# 教程

共94课时 | 6.6万人学习

C 教程
C 教程

共75课时 | 4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号