C++友元类使用场景_C++类间协作设计方式讲解
技术百科
冰川箭仙
发布时间:2026-01-01
浏览: 次 友元类是为解决特定协作场景下深度交互与封装保护的矛盾而设,如容器与迭代器、类簇构造、单元测试等,需克制使用且明确声明。
友元类不是为了“打破封装”,而是为了解决特定协作场景下,类与类之间需要深度交互但又不便暴露公有接口的矛盾。它的使用应当克制、明确且有充分理由。
需要共享内部数据结构的紧密耦合组件
当两个类在逻辑上构成一个整体,比如容器类和它的迭代器类,迭代器必须能直接访问容器的底层指针或节点结构,但把所有成员设为 public 会破坏容器的数据完整性约束。此时将迭代器声明为容器的友元类,既保证了访问效率,又维持了封装边界——只有迭代器能越界访问,其他外部代码依然被隔离。
- 典型例子:std::vector 的私有成员 _M_start、_M_finish 是其 iterator 可直接读写的,但普通用户代码完全不可见
- 注意:友元关系不传递,也不继承;A 是 B 的友元,不意味着 A 的子类或 B 的子类自动获得该权限
实现类簇(Class Cluster)时统一构造与资源管理
某些设计中,对外只暴露一个抽象接口类,而实际由多个具体实现类分工协作(如不同压缩格式的解码器)。主接口类可能需要创建并初始化这些实现类,并直接设置其私有状态(如缓冲区地址、解码上下文),但又不希望把这些初始化逻辑暴露为 public 接口。这时可将主接口类声明为各实现类的友元。
- 避免把构造参数全塞进构造函数,也避免为初始化过程添加冗余的 set_xxx() 方法
- 关键点:友元仅用于构造/配置阶段的可信协作,运行时仍通过公有接口通信
单元测试类需验证私有行为逻辑
测试代码本身不属于产品模块,但需要检查类的私有成员是否按预期更新(例如缓存命中计数、状态机当前 stage)。将测试类(如 TestMyClass)声明为被测类的友元,可在测试中直接断言私有变量值,而不必为测试破环设计——无需添加仅供测试用的 public getter。
- 建议将测试类命名清晰(如 MyClassTest),并在头文件中用 #ifdef TEST 宏控制友元声明,确保发布版不包含该关系
- 这不是偷懒替代测试设计,而是对关键不变量做白盒验证的合理手段
基本上就这些。友元类不是语法糖,而是协作契约——它让两个类在编译期就约定好“我信你,只信你”。用对了,代码更清晰;滥用,则封装形同虚设。
# 也不
# 多个
# 并在
# 迭代
# 数据结构
# 设为
# public
# c++
# class
# 指针
# 子类
# 构造函数
# 接口
# 封装
# 继承
# 单元测试
# 形同虚设
# 仅供
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- Windows家庭版如何开启组策略(gpedit.
- 跨文件调用类方法怎么用_php作用域操作符与自动加
- Win11怎么设置指纹解锁 Win11笔记本录入指
- XSLT怎么生成动态的HTML属性名和标签名
- VSC怎么创建PHP项目_从零开始搭建项目的步骤【
- 如何使用正则表达式批量替换重复的“-”模式为固定字
- Win11怎么设置虚拟键盘_打开Win11屏幕键盘
- 如何快速验证Golang安装是否成功_运行go v
- Django密码修改后会话失效的解决方案
- Win11怎么设置开机自动连接宽带_Windows
- Win11怎么打开旧版计算器_Win11恢复传统计
- SAX解析器是什么,它与DOM在处理大型XML文件
- windows 10应用商店区域怎么改_windo
- Win11怎么设置闹钟_Windows 11时钟应
- Win11怎么设置开机问候语_自定义Win11锁屏
- Windows10蓝屏代码DPC_WATCHDOG
- php嵌入式多设备通信怎么实现_php同时管理多个
- Win11怎么关闭自动调节亮度_Windows11
- 如何使用Golang实现负载均衡_分发请求到多个服
- Win11怎样彻底卸载自带应用_Win11彻底卸载
- Windows10系统怎么查看硬盘健康_Win10
- GML (Geography Markup Lan
- Mac怎么开启“任何来源”_Mac安装未签名应用的
- Win11怎么开启智能存储_Windows11存储
- 如何使用Golang进行HTTP服务性能测试_测量
- C++如何使用std::optional?(处理可
- c++中如何进行二进制文件读写_c++ read与
- c++如何获取map中所有的键_C++遍历键值对提
- c++怎么实现高并发下的无锁队列_c++ std:
- 如何在Golang中引入测试模块_Golang测试
- LINUX怎么进行文本内容搜索_Linux gre
- Win11文件夹预览图不显示怎么办_Win11缩略
- 如何在Golang中写入XML文件_生成符合规范的
- windows 10专注助手怎么关闭_window
- Win11怎么恢复出厂设置_Win11重置此电脑保
- 如何自定义Windows终端的默认配置文件?(Po
- Go 语言标准库为何不提供泛型 Contains
- Win11怎么设置DNS服务器_Windows11
- Win11快速助手怎么用_Win11远程协助连接教
- Win11怎么查看电脑配置_Win11硬件配置详细
- 如何在 Python 测试中动态配置 @backo
- Windows11怎么用“记事本”自动换行与编码
- windows如何修改文件默认打开方式_windo
- php和redis连接超时怎么办_phpredis
- 如何使用Golang安装API文档生成工具_快速生
- Win11怎么更改鼠标指针方案_Windows11
- Golang如何遍历目录文件_Golang fil
- 如何使用Golang实现RPC序列化与反序列化_G
- XML的“混合内容”是什么 怎么用DTD或XSD定
- 如何解决同一段404代码在不同主机上表现不一致的问

QQ客服