观察者模式:不将Subject设为模板类,如何传递模板变量给Observer?
解决方案:通过非模板基类+动态类型转换实现
你的核心问题是非模板类Subject无法存储模板化的Observerstd::vector<Observer<T>*>中的T无定义。下面给出一种简洁的解决思路,无需将Subject改为模板类:
核心思路
引入一个非模板的抽象基类BaseObserver,让所有模板化的Observer<T>继承它。这样Subject只需存储BaseObserver*的容器,在notify时通过动态类型转换筛选出匹配类型的观察者,调用其模板化的update方法。
完整可编译代码
#include <iostream> #include <vector> class Subject; // 所有观察者的非模板基类,仅提供统一销毁接口 class BaseObserver { public: virtual ~BaseObserver() = default; }; template<typename T> class Observer : public BaseObserver { public: virtual void update(T value, Subject*) = 0; }; class Subject { private: std::vector<BaseObserver*> _obs; public: void attach(BaseObserver* obs) { _obs.push_back(obs); } template<typename T> void notify(T value) { for (auto obs : _obs) { // 仅通知类型匹配的观察者 if (auto typed_obs = dynamic_cast<Observer<T>*>(obs)) { typed_obs->update(value, this); } } } }; template<typename T> class B : public Observer<T> { public: void update(T value, Subject* sub) override { std::cout << "Value set = " << value << std::endl; } }; template<typename T> class A : public Subject { private: T _x; public: void set(T value) { _x = value; notify(_x); // 直接传递模板类型值,Subject无需模板化 } }; int main() { A<int> a1; B<int> b1; B<double> b2; // 测试不同类型观察者,不会收到int通知 a1.attach(&b1); a1.attach(&b2); a1.set(10); // 仅b1输出:Value set = 10 A<double> a2; a2.attach(&b2); a2.set(3.14); // 仅b2输出:Value set = 3.14 return 0; }
关键细节说明
- 非模板基类
BaseObserver:解决Subject无法存储模板化Observer的问题,提供统一的基类指针类型,同时保证多态销毁避免内存泄漏。 - 动态类型转换
dynamic_cast:在notify时筛选出与当前value类型匹配的Observer,确保只有对应类型的观察者会收到通知,保证类型安全。 - 模板化的notify函数:Subject的notify是模板函数,支持任意类型的value传递,无需Subject本身模板化。
注意:使用dynamic_cast需要编译器开启RTTI(运行时类型信息),主流编译器默认已开启,若需手动开启可添加编译选项(如GCC的-frtti)。
内容的提问来源于stack exchange,提问作者xyf
相关产品推荐
相关产品推荐

