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

落涛大大_2943

落涛大大_2943

2026-02-06

396人浏览

原创

用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。

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

  • 第一阶段:遍历原始 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++ 中往往过度设计:

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

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

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

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

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

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

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

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++ 注册表 标准库

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
C++ Qt图形开发
C++ Qt图形开发

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

2025.08.15

5442

7

C++桌面程序开发
C++桌面程序开发

本专题聚焦 C++ 在桌面端图形界面应用开发中的实战应用,系统讲解 Qt 框架的信号与槽机制、界面布局管理、事件响应、数据交互、样式美化与多窗口应用设计等核心知识。通过实战案例(如记事本应用、数据管理工具、系统监控面板),帮助学习者掌握 从UI设计到完整桌面软件开发的C++工程化能力。

2025.10.23

1454

13

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

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

2025.12.05

1441

15

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

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

2025.11.27

355

14

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

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

2023.09.20

2318

7

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

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

2023.08.03

1838

5

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

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

2023.09.04

2904

5

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

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

2023.10.24

6224

49

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

2023.11.24

6069

6

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习