观察者模式在c++中通过std::function+std::vector实现解耦,subject维护回调列表并支持attach/detach/notify,可扩展为模板支持参数传递,结合weak_ptr避免悬挂指针,c++20后可选用boost.signals2等成熟库。

观察者模式在 C++ 中核心是解耦“被观察者(Subject)”和“观察者(Observer)”,让 Subject 在状态变化时自动通知所有注册的 Observer,而无需知道它们的具体类型。现代 C++ 推荐用 std::function + std::vector 实现轻量、灵活、无侵入的版本,避免传统虚函数继承带来的强耦合。
用 std::function 实现简洁版观察者模式
不依赖继承,Observer 可以是普通函数、lambda、成员函数对象,Subject 仅持有一组可调用对象。
- Subject 维护一个
std::vector<:function>></:function>存储回调 - 提供
attach()添加观察者(返回 token 用于后续 detach) - 提供
notify()遍历并调用所有已注册回调 - 为支持安全移除,可用
std::shared_ptr<:function>></:function>或索引 token(示例用后者)
示例代码:
#include <iostream>
#include <vector>
#include <functional>
#include <memory>
class Subject {
std::vector<std::function<void()>> observers_;
int next_id_ = 0;
public:
// 返回唯一 token,用于 detach
int attach(std::function<void()> obs) {
observers_.push_back(obs);
return next_id_++;
}
void detach(int id) {
if (id >= 0 && id < static_cast<int>(observers_.size())) {
observers_[id] = nullptr; // 标记为空,notify 时跳过
}
}
void notify() {
for (auto& obs : observers_) {
if (obs) obs();
}
}
};
// 使用示例
int main() {
Subject sub;
// lambda 观察者
auto id1 = sub.attach([]{ std::cout << "Observer A notified.\n"; });
// 普通函数
auto handler = []{ std::cout << "Observer B triggered.\n"; };
auto id2 = sub.attach(handler);
sub.notify(); // 输出两行
sub.detach(id1); // 移除第一个
sub.notify(); // 只输出 Observer B
return 0;
}
支持参数传递与类型安全的进阶版
实际项目中常需通知时携带数据(如新值、事件类型)。可泛化为模板类,用 std::function<void t></void> 支持任意通知类型。
立即学习“C++免费学习笔记(深入)”;
- 定义
Observer<t></t>模板,通知函数接收 const T& - Subject
存储 std::function<void t></void> - notify(const T& data) 调用所有观察者并传参
- 搭配
std::shared_ptr+ 弱引用可支持自动生命周期管理(避免悬挂指针)
结合智能指针实现自动生命周期管理
当 Observer 是某个对象的成员函数时,需防止 Subject 持有已销毁对象的 this 指针。推荐用 std::weak_ptr 包装 observer 对象,调用前 lock 判断是否有效。
- Observer 类型改为
std::function<void></void>的包装器,内部持std::weak_ptr<owner></owner> - Subject 存储
std::shared_ptr<observerwrapper></observerwrapper> - notify 中对每个 wrapper 调用
lock(),成功才执行 - 这样 Observer 所属对象析构后,通知自动跳过,无需手动 detach
C++20 后可考虑信号槽(signal-slot)库替代
若项目允许第三方依赖,Boost.Signals2 或 Corrade::Signals 提供线程安全、自动连接管理、断开检测等成熟能力,比手写更健壮。但纯头文件轻量场景,前述 std::function 方案已足够清晰实用。











