0

0

C++中如何实现简单的观察者模式?(利用虚函数接口或函数指针)

裘德小鎮的故事

裘德小鎮的故事

发布时间:2026-01-10 15:21:33

|

872人浏览过

|

来源于php中文网

原创

用纯虚函数定义Observer接口最清晰,即声明virtual void update(const std::string& event) = 0,强制子类实现,避免对象切片和运行时类型擦除,Subject用std::vector管理生命周期。

c++中如何实现简单的观察者模式?(利用虚函数接口或函数指针)

用纯虚函数定义 Observer 接口最清晰

虚函数接口是 C++ 观察者模式最常用、最符合面向对象语义的方式。关键在于把 update 声明为纯虚函数,强制子类实现,同时避免对象切片和运行时类型擦除问题。

常见错误是直接在基类里提供空的 update 实现(非纯虚),导致派生类忘记重写却无编译报错;或者用 std::function 替代接口,失去静态多态和零开销抽象的优势。

  • Observer 基类只含一个纯虚函数 virtual void update(const std::string& event) = 0;
  • Subject 持有 std::vector<:unique_ptr>>,避免裸指针生命周期失控
  • 注册时用 std::move 转移所有权,禁止拷贝 Observer 对象(可删掉拷贝构造/赋值)
  • 通知时遍历容器调用 obs->update(event),多态分发由 vtable 完成,无额外开销
class Observer {
public:
    virtual ~Observer() = default;
    virtual void update(const std::string& event) = 0;
};

class Subject { std::vector> observers; public: void attach(std::unique_ptr obs) { observers.push_back(std::move(obs)); } void notify(const std::string& event) { for (const auto& obs : observers) { obs->update(event); } } };

用函数指针实现轻量级回调需注意调用约定

函数指针适合极简场景(比如嵌入式或性能敏感模块),但无法捕获对象状态,必须搭配上下文参数或静态成员函数使用。容易踩的坑是传入普通成员函数地址——它不是自由函数,不能直接转成 void(*)()

若要绑定对象实例,必须用静态成员 + void* 上下文,或改用 std::function(但已偏离“函数指针”本意)。

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

造梦阁AI
造梦阁AI

AI小说推文一键成片,你的故事值得被看见

下载
  • 自由函数指针签名应为 void (*)(const char*, void*),第二个参数用于传递 this
  • 注册时保存函数指针和 void* 上下文,通知时一并传入
  • 不能直接存 &MyClass::onUpdate —— 编译失败,成员函数指针与普通指针不兼容
  • 相比虚函数,少了类型安全和自动内存管理,易出现悬空指针或类型误传
using Callback = void (*)(const char*, void*);

class SubjectFP { struct Handler { Callback fn; void ctx; }; std::vector handlers; public: void attach(Callback fn, void ctx) { handlers.push_back({fn, ctx}); } void notify(const char* event) { for (const auto& h : handlers) { h.fn(event, h.ctx); } } };

// 使用示例: void log_update(const char e, void obj) { std::cout << "Log: " << e << "\n"; }

std::function + lambda 是折中方案,但有额外开销

如果需要捕获局部变量或快速原型验证,std::function 配合 lambda 最方便。但它底层可能触发堆分配(当闭包对象较大时),且每次调用有间接跳转开销,不适合高频通知路径。

另一个问题是生命周期管理:lambda 捕获局部变量后,若 Subject 生命周期长于该变量,就会变成悬空引用。必须确保捕获的是值([=])或显式延长依赖对象寿命。

  • 声明容器为 std::vector<:function std::string>>
  • 注册时可直接写 [&obj]() { obj.handle(); },但注意 obj 必须比 Subject 活得久
  • 比起虚函数,少了编译期多态,调试时帧更难追踪(内联受限)
  • 如需零开销,应回退到虚函数接口;如需灵活性,接受这点开销也合理

观察者生命周期管理是核心难点

无论用哪种方式,最大的实际问题不是语法怎么写,而是谁负责销毁观察者、何时从 Subject 中移除。C++ 没有弱引用原语,std::weak_ptr 只适用于共享所有权场景,而多数观察者是独占或栈上对象。

虚函数方案中,Subject 持有 unique_ptr 表示强拥有,意味着观察者不能独立于 Subject 存活;函数指针方案则完全无所有权语义,全靠程序员手动保证有效性。这是所有 C++ 观察者实现中最容易出 bug 的地方。

  • 不要让 Subject 持有裸指针或引用
  • 若观察者是栈对象,注册前必须确认其作用域覆盖整个通知周期
  • 提供 detach() 接口,允许观察者主动注销(需在 Observer 析构时调用)
  • 考虑用信号槽库(如 libsigc++ 或 Qt)替代手写,它们内置了连接管理和自动断连

相关专题

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

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

3438

2023.10.31

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

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

68

2025.08.15

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

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

53

2025.12.05

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

315

2023.08.02

go语言 面向对象
go语言 面向对象

本专题整合了go语言面向对象相关内容,阅读专题下面的文章了解更多详细内容。

56

2025.09.05

java面向对象
java面向对象

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

49

2025.11.27

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

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

15

2025.11.27

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

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

523

2023.09.20

Golang gRPC 服务开发与Protobuf实战
Golang gRPC 服务开发与Protobuf实战

本专题系统讲解 Golang 在 gRPC 服务开发中的完整实践,涵盖 Protobuf 定义与代码生成、gRPC 服务端与客户端实现、流式 RPC(Unary/Server/Client/Bidirectional)、错误处理、拦截器、中间件以及与 HTTP/REST 的对接方案。通过实际案例,帮助学习者掌握 使用 Go 构建高性能、强类型、可扩展的 RPC 服务体系,适用于微服务与内部系统通信场景。

8

2026.01.15

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1.0万人学习

进程与SOCKET
进程与SOCKET

共6课时 | 0.3万人学习

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

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