0

0

C++怎么实现观察者模式_C++事件机制教程【解耦】

裘德小鎮的故事

裘德小鎮的故事

发布时间:2026-02-27 12:36:41

|

915人浏览过

|

来源于php中文网

原创

用 std::function + std::vector 可实现轻量观察者模式,核心是运行时回调抽象与安全生命周期管理,避免虚函数耦合和悬挂调用。

c++怎么实现观察者模式_c++事件机制教程【解耦】

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

不用第三方库、不依赖 Qt 或 Boost,纯标准 C++ 就能搭出可用的观察者链。核心是把回调抽象成 std::function<void></void>(或带参数的变体),用 std::vector 存储,触发时遍历调用。

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

  • 推荐签名:using Callback = std::function<void event>;</void>Event 是自定义结构体,比 void* 安全、比模板泛型易维护
  • 注册时别写 obs.register([]{ /* 用局部变量 */ }); —— 捕获栈变量的 lambda 一出作用域就失效
  • 移除回调不能只靠 erase 迭代器,得配套实现 ID 或比较逻辑,否则无法安全解绑

为什么不用虚函数多态实现 Observer 接口

传统教科书写法是定义 Observer 抽象基类,让具体类继承并重写 update()。这在 C++ 里容易引发两个实际问题:内存布局耦合和销毁顺序风险。

当被观察者持有 std::vector<:unique_ptr>></:unique_ptr>,而某个 Observer 子类对象自身又持有被观察者引用(比如 UI 控件监听数据模型),就极易形成循环引用或析构时访问已释放内存。用 std::function 则天然解耦类型,回调绑定发生在运行时,不强制继承关系。

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

  • 虚函数方案要求所有观察者从同一基类派生,限制了现有类的复用(比如你不能让一个 std::thread 对象直接当 observer)
  • 虚表指针带来微小但确定的内存与调用开销;std::function 在 clang/gcc 下对空捕获 lambda 通常内联为直接调用
  • 调试时,虚函数调用栈深、符号模糊;std::function 调用点清晰,gdb 里能直接看到注册位置

std::weak_ptr 配合 std::shared_ptr 解决悬挂回调

最常被忽略的坑:UI 控件作为观察者被销毁了,但被观察者还留着它的 std::function 回调,下次通知直接 crash。解决方案不是禁止销毁,而是让回调“知道自己是否还有效”。

Spell.tools
Spell.tools

高颜值AI内容营销创作工具

下载

做法是观察者对象用 std::shared_ptr 管理,注册时传入 std::weak_ptr 包装的 lambda:

auto self = shared_from_this();
obs.register([self](const Event& e) {
    if (auto ptr = self.lock()) {
        ptr->handle(e);
    } // 否则静默丢弃
});

这要求观察者类继承 std::enable_shared_from_this,且必须由 std::make_shared 构造。硬伤是:不能用于栈对象或全局对象——它们根本没法套 shared_ptr

  • 别试图用 std::weak_ptr 包裹 std::function 本身——std::function 不支持 weak 语义
  • 如果观察者是普通类实例(非 shared_ptr 管理),只能靠手动 unregister,且必须保证 unregister 调用早于对象析构
  • Qt 的 QObject::connect 默认做类似 weak 检查,但那是元对象系统 baked in 的行为,标准 C++ 得自己铺路

性能敏感场景下避免 std::function 的堆分配

每次 std::function 构造都可能触发一次小内存分配(尤其捕获较多变量时),高频事件(如帧更新、音频采样)中会明显拖慢吞吐。这时候得降级到函数指针 + void* 上下文,或用 std::variant 预设几种回调形态。

更务实的做法是:先用 std::function 快速验证逻辑,再针对 hot path 优化。例如把最常用的无参回调单独抽成 std::array<:function>, 8></:function>,固定大小避免动态扩容。

  • Clang/GCC 对空捕获 lambda 转 std::function 通常零开销;但捕获 3 个以上变量,大概率触发堆分配
  • sizeof(std::function<void>) == 32</void>(常见值)可粗略判断是否溢出 small buffer optimization
  • 别过早优化:95% 的业务事件(配置变更、网络响应)完全不需要考虑这点,先跑通再测

真正难的从来不是怎么写完一个观察者,而是想清楚谁拥有谁、谁决定谁的生命周期、以及通知失败时要不要重试或丢弃——这些不会出现在类图里,但每一条都直接对应 core dump 或数据不一致。

热门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中文网欢迎大家前来学习。

3821

2023.10.31

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

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

72

2025.08.15

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

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

97

2025.12.05

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

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

27

2025.11.27

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

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

27

2025.11.27

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

385

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

200

2025.07.04

javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

183

2023.11.23

Golang 并发编程模型与工程实践:从语言特性到系统性能
Golang 并发编程模型与工程实践:从语言特性到系统性能

本专题系统讲解 Golang 并发编程模型,从语言级特性出发,深入理解 goroutine、channel 与调度机制。结合工程实践,分析并发设计模式、性能瓶颈与资源控制策略,帮助将并发能力有效转化为稳定、可扩展的系统性能优势。

0

2026.02.27

热门下载

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

精品课程

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

共94课时 | 10.3万人学习

C 教程
C 教程

共75课时 | 5万人学习

C++教程
C++教程

共115课时 | 19.7万人学习

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

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