绕过事件模板化虚函数
Way around templated virtual function for events
我基本上是在尝试实现一个通用的观察者模式。
class Observer {
public:
template <class T>
virtual void OnEvent(const EventHandle& h, T& affectedItem) = 0;
};
class Subject {
public:
void AddObserver(Observer* o) {
observers.Add(o);
}
void RemoveObserver(Observer* o) {
observers.Remove(o);
}
template <class T>
void Notify(const EventHandle& h, T& affectedItem) {
for (Observer* o : observers) {
o->OnEvent(h, affectedItem);
}
}
private:
set<Observer*> observers;
};
在Observer::OnEvent()
中,我想获得在事件中受到影响的道具(假设我刚刚向库存中添加了一些东西,并且需要在GUI中反映添加的内容——我会调用Subject::Notify(itemAddedEvent, newItem)
)。我知道我需要重构/重新设计一些类,但我不知道怎么做。有什么方法可以解决这个问题呢?
不幸的是,正如您在编译时可能看到的那样,不允许为虚函数使用模板。
既然您选择了虚函数,我猜您打算以某种方式使用多态性。如果是这种情况,您完全可以使用使用继承的无模板实现。唯一的约束是不同的角色继承自泛型类。但由于可能存在多重继承,这并不是一个强约束。
观察者可能看起来像(我已经使用Subject作为受影响的项目,但你可以使用第三个类):
class Subject;
class Observer {
public:
virtual void OnEvent(const EventHandle& h, Subject& affectedItem) = 0;
virtual ~Observer() {} // virtual function ? => better foresee a virtual destructor
};
观察结果将保持几乎不变:
class Subject {
public:
...
void Notify(const EventHandle& h, Subject& affectedItem) {
for (Observer* o : observers) {
o->OnEvent(h, affectedItem);
}
}
private:
set<Observer*> observers;
};
using类就像:
struct ConcreteObserverA : Observer {
void OnEvent(const EventHandle& h, Subject& affectedItem) override {
cout<<"A:"<<&affectedItem<<endl;
}
struct ConcreteSubjectSA : Subject { };
这里有一个现场演示。
真的需要一个快速的解决方案,所以想到了这个。我意识到这是可怕的黑客,我可能破坏了编程的原则,我应该把我的电脑扔出窗外,以弥补我甚至提出这个解决方案的罪过,等等,但它确实是我想要的,而且很容易理解,所以现在我要继续使用它,直到更好的东西出现。
基本上,我只是把(可能是原始的)数据包装在一个对象中:
struct ParamBase {};
template <class T>
struct ConcreteParam : ParamBase {
T data;
ConcreteParam(T t) : data(t) {}
};
class Observer {
public:
virtual void OnEvent(const EventHandle& h, const ParamBase& affectedItem) = 0;
protected:
template <class T>
T getParamData(const ParamBase& p) {
const ParamBase* pb = &p;
return ((ConcreteParam<T>*)pb)->data;
}
};
class Subject {
public:
// Add/Remove functions stripped
template <class T>
void Notify(const EventHandle& h, T affectedItem) {
for (Observer* o : observers) {
o->OnEvent(h, ConcreteParam<T>(affectedItem));
}
}
};
使用例子:
class InventoryUI : public Observer {
public:
virtual void OnEvent(const EventHandle& h, const ParamBase& affectedItem) {
if (h == itemRemovedEvent) {
int index = getParamData<int>(affectedItem);
removeItemAt(index);
}
else if (h == itemAddedEvent) {
Item* item = getParamData<Item*>(affectedItem);
addItemToGrid(item);
}
}
};
相关文章:
- 返回ERROR_INVALID_PARAMETER的事件日志函数
- 尝试使用 EvtSetChannelConfigProperty() 函数更新最大事件日志文件大小时插入的错误值
- SFML c ++ 当包含文件内游戏中发生事件时,如何使用铃声函数为我的游戏创建声音类?
- 从C++回调函数发出节点.js事件
- 将函数名称传递给事件总线系统中的事件类
- std::函数,带有 SDL 事件回调的 lambda 错误
- 如何将lambda函数排队到Qt的事件循环中?
- 事件与提升::函数
- 键按下事件错误 Qt 实现函数时
- ``pollout''Linux函数中的“ Pollout”事件是什么意思
- C++:使用回调函数作为事件通知程序
- 使用C++11 lambda函数将点击事件连接到函数时出现问题
- 创建指向成员函数的非常量指针,以便进行 SDL 事件筛选
- 在C++中为多个函数和事件重用一个线程(基本上是 POSIX 线程)
- 声明在 Qt 中发生鼠标事件时调用的函数
- 如何在 Windows 窗体中为事件函数定义使用单独的.cpp文件
- 信号处理程序与虚拟函数和继承(事件处理)
- Qt从其他线程向事件循环添加函数调用
- 复制STL:删除元素、用户定义函数作为参数和事件队列
- Nodejs C++事件发射器.加载项错误.MakeCallback中没有函数.method=发出中止陷阱:6