0

0

c++中如何实现观察者模式_c++设计模式之观察者模式

穿越時空

穿越時空

发布时间:2026-01-05 16:42:50

|

525人浏览过

|

来源于php中文网

原创

Observer接口应定义为纯虚基类,update()接收Subject&参数以避免反向依赖;Subject用std::vector管理观察者,通知前lock()确保安全;亦可选用std::function+lambda简化轻量场景。

c++中如何实现观察者模式_c++设计模式之观察者模式

Observer 接口设计要支持多态和解耦

观察者模式的核心是让被观察者(Subject)不依赖具体观察者类型,只依赖抽象接口。C++ 中最直接的方式是定义纯虚基类 Observer,所有具体观察者继承它并实现 update()。注意:不要在基类中持有 Subject* 指针——这会引入反向依赖;应由 Subject 在通知时把自身作为参数传入,例如 virtual void update(Subject& subject) = 0;

常见错误是让 Observer 持有 Subject 的强引用(如 std::shared_ptr),导致循环引用。正确做法是用弱引用(std::weak_ptr)或干脆不存——通知时由 Subject 主动传递必要数据(如状态值、事件枚举),而非暴露自身指针。

Subject 管理观察者列表要用 weak_ptr 防止悬挂

Subject 内部通常用容器保存观察者指针。若用 std::vector<:shared_ptr>>,当某个 Observer 对象析构时,Subject 仍持有其 shared_ptr,后续调用会触发未定义行为。解决方案是改用 std::vector<:weak_ptr>>,每次通知前先 lock()

for (auto& obs_wptr : observers_) {
    if (auto obs_ptr = obs_wptr.lock()) {
        obs_ptr->update(*this);
    }
}

这样既避免了悬挂指针,又不需要手动维护注册/注销逻辑。但要注意:如果 Observer 析构发生在 Subject 通知过程中,lock() 返回空,自动跳过——这是预期行为,不是 bug。

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

ChatMind
ChatMind

ChatMind是一款AI生成思维导图的效率工具,可以通过AI对话生成和编辑思维导图。

下载

std::function + lambda 可替代传统 Observer 类

对轻量级场景(比如 UI 控件状态变更通知),不必强制写完整类。Subject 可以用 std::vector<:function std::string>> callbacks_; 存储回调,注册时直接传 lambda:

subject.on_change([](const std::string& msg) {
    std::cout << "Got: " << msg << "\n";
});

优势是零继承开销、灵活捕获上下文;缺点是无法在运行时区分回调来源,也不便于统一移除(除非返回 token 或用 std::any 封装句柄)。若需取消订阅,建议配合 std::any 或返回一个 std::size_t 索引用于 remove_callback(index)

线程安全不能靠“感觉”,得明确加锁粒度

多个线程可能同时调用 attach()detach() 或触发 notify()。最稳妥的是给整个观察者容器加互斥锁(如 mutable std::mutex mtx_;),所有访问都 lock-guard。但要注意:在 notify() 中调用外部回调时,**必须释放锁后再调用**,否则可能引发死锁(回调里又去调 Subject 其他方法)。

  • 错误写法:锁住整个 notify 循环,然后在锁内调用 obs->update()
  • 正确写法:先拷贝一份存活的 observer 指针列表(在锁内完成),释放锁,再遍历调用

如果 Subject 本身已是线程安全类,那观察者列表的线程安全就是它的责任——这点常被忽略,结果在多线程环境里 crash 得莫名其妙。

相关文章

c++速学教程(入门到精通)
c++速学教程(入门到精通)

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

下载

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

相关专题

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

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

15

2025.11.27

登录token无效
登录token无效

登录token无效解决方法:1、检查token的有效期限,如果token已经过期,需要重新获取一个新的token;2、检查token的签名,如果签名不正确,需要重新获取一个新的token;3、检查密钥的正确性,如果密钥不正确,需要重新获取一个新的token;4、使用HTTPS协议传输token,建议使用HTTPS协议进行传输 ;5、使用双因素认证,双因素认证可以提高账户的安全性。

6062

2023.09.14

登录token无效怎么办
登录token无效怎么办

登录token无效的解决办法有检查Token是否过期、检查Token是否正确、检查Token是否被篡改、检查Token是否与用户匹配、清除缓存或Cookie、检查网络连接和服务器状态、重新登录或请求新的Token、联系技术支持或开发人员等。本专题为大家提供token相关的文章、下载、课程内容,供大家免费下载体验。

789

2023.09.14

token怎么获取
token怎么获取

获取token值的方法:1、小程序调用“wx.login()”获取 临时登录凭证code,并回传到开发者服务器;2、开发者服务器以code换取,用户唯一标识openid和会话密钥“session_key”。想了解更详细的内容,可以阅读本专题下面的文章。

1053

2023.12.21

token什么意思
token什么意思

token是一种用于表示用户权限、记录交易信息、支付虚拟货币的数字货币。可以用来在特定的网络上进行交易,用来购买或出售特定的虚拟货币,也可以用来支付特定的服务费用。想了解更多token什么意思的相关内容可以访问本专题下面的文章。

1156

2024.03.01

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

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

174

2023.11.23

java中void的含义
java中void的含义

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

94

2025.11.27

lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

202

2023.09.15

漫蛙2入口地址合集
漫蛙2入口地址合集

本专题整合了漫蛙2入口汇总,阅读专题下面的文章了解更多详细内容。

162

2026.01.06

热门下载

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

精品课程

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

共94课时 | 6.2万人学习

C 教程
C 教程

共75课时 | 3.9万人学习

C++教程
C++教程

共115课时 | 11.3万人学习

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

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