我想写一个类似C#的C ++事件类:
template< typename ListenerType >
class Event
{
private:
std::vector< ListenerType * > m_aListeners;
public:
void operator += ( ListenerType * pListener )
{
m_aListeners.push_back( pListener );
}
void operator -= ( ListenerType * pListener )
{
std::vector< ListenerType * >::reverse_iterator revIter = m_aListeners.rbegin();
for( ; revIter != m_aListeners.rend(); ++revIter )
if( revIter == pListener )
{
m_aListeners.remove( revIter );
break;
}
}
};
class DataReceivedEvent : public Event< DataReceivedListener >
{
public:
void Trigger( const byte_t * pData )
{
for( size_t nI = 0; nI < m_aListeners.size(); ++nI )
m_aListeners[ nI ]->OnDataReceived( pData );
}
}
问题在于它迫使我编写一个Trigger
方法,它总是为每个事件类型做同样的事情(迭代和调用处理程序),因为不同的事件可以有不同的参数列表,并且对于每个事件,关联的处理程序类型有一个具有特定名称的方法。
我对C ++ 11了解不多,但我觉得可以避免使用模板为每种事件类型重写Trigger方法。 但我不能使用C ++ 11,所以我想知道是否有一种方法,使用较旧的C ++版本,以类型安全的方式做到这一点。
编辑:我考虑创建一个事件数据类的层次结构,即template< typename ListenerType >::Data
和DataReceivedEvent::Data : public template< typename ListenerType >::Data
,这样我就可以使用一个Trigger方法始终采用单个参数,即virtual void Trigger( const Data * pData )
。但我仍然遇到需要在事件监听器中调用特定方法的问题。
答案 0 :(得分:0)
您也可以使用模板和运算符重载。当您假设ListenerType
实现operator()
时,您可以像这样实现它(该示例也使用variadic templates。您可以使用任意数量的参数):
#include <vector>
#include <iostream>
template< typename ListenerType >
class Event
{
private:
std::vector< ListenerType * > m_aListeners;
public:
void operator += ( ListenerType * pListener )
{
m_aListeners.push_back( pListener );
}
void operator -= ( ListenerType * pListener )
{
auto revIter = m_aListeners.rbegin();
for( ; revIter != m_aListeners.rend(); ++revIter )
if( revIter == pListener )
{
m_aListeners.remove( revIter );
break;
}
}
template<typename... Params>
void operator()(Params... data) {
for (auto l : m_aListeners) {
(*l)(data...);
}
}
};
class DataReceivedListener {
public:
void operator()(const char* pData) {
std::cout << pData << std::endl;
}
};
class DataReceivedEvent : public Event< DataReceivedListener >
{
public:
};
int main() {
DataReceivedEvent e;
DataReceivedListener l1;
DataReceivedListener l2;
e += &l1;
e += &l2;
e("Hello");
}
不幸的是,C ++ 11没有引入Concepts。如果你有这个(constraints in C#),你会得到编译器的更多帮助。