0

0

C++中如何实现简单的观察者模式_C++解耦组件间通信方法【设计】

冰火之心

冰火之心

发布时间:2026-02-06 15:31:03

|

356人浏览过

|

来源于php中文网

原创

用std::function+std::vector可轻量实现观察者模式,核心是存储回调并遍历通知;需规避悬空指针、迭代器失效及自我注销问题,推荐结合weak_ptr/shared_ptr管理生命周期,比虚函数继承更灵活高效。

c++中如何实现简单的观察者模式_c++解耦组件间通信方法【设计】

std::function + std::vector 实现轻量观察者注册表

不需要引入第三方库或复杂基类,C++11 起就能靠标准库搭出可用的观察者模式。核心是把回调抽象为 std::function(或带参数的变体),用 std::vector 存储,注册即 push_back,通知即遍历调用。

常见错误是直接存裸函数指针或 lambda 捕获局部变量,导致调用时悬空。必须确保回调对象生命周期长于观察者容器,或用 std::shared_ptr 管理。

  • 推荐签名: using Callback = std::function;Event 是自定义结构体,比 void* 安全、比模板泛型更易维护
  • 注册时检查重复:可加 std::weak_ptr 配合 std::shared_ptr 实现自动去重与自动注销
  • 通知时避免迭代器失效:若回调内可能调用 unregister(),需先拷贝回调列表再遍历

如何安全处理观察者在回调中自我注销

这是最常踩的坑:遍历时删除容器元素,引发迭代器失效和未定义行为。不能边 for-range 边 erase。

正确做法是分离“通知”和“清理”。先收集待移除项,或改用索引遍历并倒序删,但更稳妥的是两阶段策略:

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

  • 第一阶段:遍历原始 std::vector<:weak_ptr>>,调用 lock() 获取有效回调,存入临时 std::vector<:function>>
  • 第二阶段:遍历临时列表执行调用;结束后再扫描原容器,erase 已过期的 weak_ptr
  • 如果不用智能指针,就要求调用方显式调用 unregister(),并在容器内部用 std::list 替代 std::vector,支持 O(1) 删除

为什么不用虚函数+继承实现?

纯虚基类(如 class Observer { virtual void onEvent(const Event&) = 0; };)看似经典,但在现代 C++ 中往往过度设计:

  • 每个具体观察者都要继承、实现虚函数,增加编译依赖和头文件耦合
  • 多态调用有虚表开销,虽小但对高频事件(如游戏帧更新)可测出差异
  • 无法直接绑定成员函数而不传对象指针,需额外包装(std::bind 或 lambda),反而不如 std::function 直观
  • 不支持无状态函数、静态函数、函数对象等灵活来源

除非你已有严格接口契约、需要运行时动态切换观察者类型,否则没必要上继承体系。

Qt 的 QObject::connect() 和标准库方案本质区别在哪

Qt 版本不是“更高级”,而是为特定场景深度优化:信号与槽自动管理对象生命周期(父对象析构时自动断连)、线程安全(跨线程队列投递)、元对象系统支持字符串名连接。这些都以宏、moc 编译器和运行时开销为代价。

标准库方案没这些——它也不该有。如果你的模块不涉及 GUI、不跨线程通信、不需要运行时反射,硬套 Qt 机制反而让逻辑变得隐晦且难测试。

真正要注意的是:Qt 的连接默认是 Qt::AutoConnection,跨线程时会排队,而手写方案默认是同步调用,想异步必须自己扔进 std::threadstd::async,这点容易忽略。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
视频后缀名都有哪些
视频后缀名都有哪些

视频后缀名都有avi、mpg、mpeg、rm、rmvb、flv、wmv、mov、mkv、ASF、M1V、M2V、MPE、QT、VOB、RA、RMJ、RMS、RAM、等等。更多关于视频后缀名的相关知识,详情请看本专题下面的文章,php中文网欢迎大家前来学习。

3579

2023.10.31

C++ Qt图形开发
C++ Qt图形开发

本专题专注于 C++ Qt框架在图形界面开发中的应用,系统讲解窗口设计、信号与槽机制、界面布局、事件处理、数据库连接与跨平台打包等核心技能,通过多个桌面应用项目实战,帮助学员快速掌握 Qt 框架并独立完成跨平台GUI软件的开发。

71

2025.08.15

C++ 图形界面开发基础(Qt方向)
C++ 图形界面开发基础(Qt方向)

本专题系统讲解 使用 C++ 与 Qt 进行图形界面(GUI)开发的核心技能,内容涵盖 Qt 项目结构、窗口组件、信号与槽机制、事件处理、布局管理、资源管理,以及跨平台编译与打包流程。通过多个小型桌面应用实战案例,帮助学习者掌握从界面设计到功能实现的完整 GUI 开发能力。

82

2025.12.05

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

17

2025.11.27

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

537

2023.09.20

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

402

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

213

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1512

2023.10.24

1688阿里巴巴货源平台入口与批发采购指南
1688阿里巴巴货源平台入口与批发采购指南

本专题整理了1688阿里巴巴批发进货平台的最新入口地址与在线采购指南,帮助用户快速找到官方网站入口,了解如何进行批发采购、货源选择以及厂家直销等功能,提升采购效率与平台使用体验。

49

2026.02.06

热门下载

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

精品课程

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

共94课时 | 8.7万人学习

C 教程
C 教程

共75课时 | 4.5万人学习

C++教程
C++教程

共115课时 | 16.2万人学习

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

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