我正在创建一个简单的事件系统,其中可以针对特定主题通知多个侦听器,并且当触发事件时,它可以将通用有效负载传递给事件,并且侦听器将匹配触发事件的格式。但是,由于无法在虚拟函数上使用模板,我还能做到这一点吗?
class AEventListener
{
public:
template<class T>
struct PayloadObject {
T obj;
};
explicit AEventListener();
virtual ~AEventListener();
//error here because T is undefined. Each PayloadObject may have a different type
virtual void notify(vector<shared_ptr<PayloadObject<T>>> payload) = 0;
};
当事件主题订阅了一个侦听器时,会调用notify方法,但我想要一种只是将一大堆随机对象传递给侦听器的通用方法。
例如
fireEvent("test.topic", Payload { 0, "hello", 123 });
//...
listener.notify(payload);
我将如何在C ++中使用它?
我设法绕过这个,虽然我不认为这是最好的方式,可能会降低性能。
template<class T>
struct PayloadObject : public APayloadObject {
T obj;
PayloadObject(T obj) {
this->obj = obj;
}
~PayloadObject() override {
};
};
struct APayloadObject {
virtual ~APayloadObject();
};
烧成:
vector<shared_ptr<APayloadObject>> payload;
payload.push_back(shared_ptr<PayloadObject<int>>(new PayloadObject<int>(5))); //payload[0] = int - 5
Events::fire(EventKeys::DISCONNECTION_EVENT, payload);
通知:
shared_ptr<PayloadObject<int>> number = dynamic_pointer_cast<PayloadObject<int>>(payload[0]);
int id = number.get()->obj; //payload[0] = int - 5
答案 0 :(得分:2)
一种简单的方法是为Payload对象提供公共基础或公共接口。所以它们不是模板类。
struct Payload {
virtual ~Payload() = default;
virtual std::string foo() const;
virtual std::string bar() const;
};
另一种方法是为有效负载对象使用变量类型:
using Message_t = boost::variant<A, B, C>;
然后让AEventListener
采用Message_t
类型,这样就不需要将成员函数作为模板。
class AEventListener
{
public:
virtual ~AEventListener();
virtual void notify(std::vector<Message_t> payload) = 0;
};
在C ++ 17中,您可以使用std::variant
代替boost。
另一种方法是跳过使用变体,只需使它成为监听器必须实现三种不同的功能,每种类型一种:
class AEventListener
{
public:
virtual ~AEventListener();
virtual void notifyA(A payload) = 0;
virtual void notifyB(B payload) = 0;
virtual void notifyC(C payload) = 0;
};
更一般地说,在C ++中很难创建类似&#34;可以使用任何特定类型的参数调用的函数对象&#34;。这部分原因是因为......它不是很有用,你可以用任何类型的数据来做一些你不能做的事情。
所以我建议你仔细考虑改进你的事件监听器概念,并更具体地说明这类对象应该被认为是必须要做的。