C#中的事件機制可以很方便的實現(xiàn)設(shè)計模式中的Observer模式,C#提供了delegate 和 event 來實現(xiàn)這種機制,實際上只要delagate就可以實現(xiàn)event效果,event語法完全沒必要,因為delegate是多播的。本文提供了一個C++版本的實現(xiàn),與C#原生的事件機制相比,只有一點不同,我實現(xiàn)的delegate是單播的(為了避免delegate 和 event 功能重復(fù)的問題)。
C# delegate 本質(zhì)上是一個函數(shù)的面向?qū)ο蟮姆庋b, 在C++語言中函數(shù)分好多種,包括 全局函數(shù),成員函數(shù),函數(shù)對象(即functor,雖然不是函數(shù),但因為行為像函數(shù),所以歸為函數(shù)一類),考試.大提示因此在C++里實現(xiàn)delegate的關(guān)鍵就是封裝上述3類函數(shù)的不同,對外提供一致的接口,先來看一下delegate的實現(xiàn)。
template
class Delegate
{
public:
Delegate(){}
virtual ~Delegate(){}
public:
typedef TReturn (*InvokerType)(TArgument args);
// for global or static methods
Delegate(TReturn (*pCallback)(TArgument))
:m_pInvoker(NULL)
{
Invoker::Bind(pCallback);
m_pInvoker = Invoker::Invoke;
}
// for object member methods
template
Delegate(TObject* pObject, TReturn (TObject::*pCallback)(TArgument))
:m_pInvoker(NULL)
{
MemberInvoker::Bind(pObject,pCallback);
m_pInvoker = MemberInvoker::Invoke;
}
// for functor methods
template
Delegate(TFunctor* pCallback)
:m_pInvoker(NULL)
{
FunctorInvoker::Bind(pCallback);
m_pInvoker = FunctorInvoker::Invoke;
}
TReturn operator() (TArgument args)
{
return m_pInvoker(args);
}
//implementations
private:
InvokerType m_pInvoker;
};
delegate 本身就是一個函數(shù)對象,針對C++里3類函數(shù)提供了3個構(gòu)造函數(shù),每個構(gòu)造函數(shù)的實現(xiàn)分別用到了一個輔助類別,分別是Invoker(用于全局函數(shù)或者類的靜態(tài)函數(shù)),MemberInvoker(用于類成員函數(shù)),F(xiàn)unctorInvoker(用于functor) ,這三個輔助類別主要用于在編譯時保存函數(shù)類型,對象類型等信息。實現(xiàn)如下:
template
struct Invoker
{
typedef TReturn (*Method)(TArgument args);
static TReturn Invoke(TArgument args)
{
return m_pCallback(args);
}
static void Bind(Method pCallback)
{
m_pCallback = pCallback;
}
private:
static Method m_pCallback;
};
template
typename Invoker::Method Invoker::m_pCallback = NULL;
template
struct MemberInvoker
{
typedef TReturn (TObject::*MemberMethod)(TArgument);
static TReturn Invoke(TArgument args)
{
return (m_pObject->*m_pCallback)(args);
}
static void Bind(TObject* pObject,MemberMethod pCallback)
{
m_pObject = pObject;
m_pCallback = pCallback;
}
private:
static TObject* m_pObject;
static MemberMethod m_pCallback;
};
template
TObject* MemberInvoker::m_pObject = NULL;
template
typename MemberInvoker::MemberMethod MemberInvoker::m_pCallback = NULL;
template
struct FunctorInvoker
{
typedef TFunctor* FunctorMethod;
static TReturn Invoke(TArgument args)
{
return m_pCallback(args);
}
static void Bind(FunctorMethod pCallback)
{
m_pCallback = pCallback;
}
private:
static FunctorMethod m_pCallback;
};
template
typename FunctorInvoker::FunctorMethod FunctorInvoker::m_pCallback = NULL;
至此,一個完整的delegate實現(xiàn)完畢,我們可以用它來實現(xiàn)event 了。
event實現(xiàn)如下,為了實現(xiàn)多播用std::list保存多個deledate:
template< class TReturn, class TArgument>
class Event
{
public:
typedef TReturn ReturnValue;
typedef TArgument EventArgs;
typedef Delegate EventHandler;
public:
Event(){}
virtual ~Event(){}
public:
ReturnValue GetReturnValue(const EventHandler& rhs )
{
return m_ReturnValue[rhs];
}
ReturnValue operator() (EventArgs/* const& */rhs)
{
ReturnValue RetValue;
for (std::list::iterator i = m_Handler.begin(); i != m_Handler.end(); ++i)
{
RetValue = (*i)(rhs);
m_ReturnValue[(*i)] = RetValue;
}
return RetValue;
}
Event& operator+= ( EventHandler/* const& */rhs )
{
m_Handler.push_back(rhs);
return *this;
}
Event& operator-= ( EventHandler/* const& */rhs )
{
m_Handler.remove(rhs);
return *this;
}
private:
std::list m_Handler;
std::map m_ReturnValue;
};
event重載了+=, -=操作符,使用上完全跟C#原生的event操作基本一樣。event實際上就是一個多播delegate,如果不需要多播,直接使用delegate就可以了。
目前的實現(xiàn)還有一些小問題:
1.目前event不支持void返回類型,其實只要寫一個event偏特化就可,因為我是在VC6下寫的代碼,而VC6不支持模板偏特化
2. 由于C++語言對模板的一些限制,不得以在頭文件中定義了一些靜態(tài)成員變量,所以當在多個.cpp文件中包含這個頭文件時會有鏈接錯誤,VC下可以使用_declspec(selectany)解決這個問題,別的編譯器我就不知道了。
C# delegate 本質(zhì)上是一個函數(shù)的面向?qū)ο蟮姆庋b, 在C++語言中函數(shù)分好多種,包括 全局函數(shù),成員函數(shù),函數(shù)對象(即functor,雖然不是函數(shù),但因為行為像函數(shù),所以歸為函數(shù)一類),考試.大提示因此在C++里實現(xiàn)delegate的關(guān)鍵就是封裝上述3類函數(shù)的不同,對外提供一致的接口,先來看一下delegate的實現(xiàn)。
template
class Delegate
{
public:
Delegate(){}
virtual ~Delegate(){}
public:
typedef TReturn (*InvokerType)(TArgument args);
// for global or static methods
Delegate(TReturn (*pCallback)(TArgument))
:m_pInvoker(NULL)
{
Invoker
m_pInvoker = Invoker
}
// for object member methods
template
Delegate(TObject* pObject, TReturn (TObject::*pCallback)(TArgument))
:m_pInvoker(NULL)
{
MemberInvoker
m_pInvoker = MemberInvoker
}
// for functor methods
template
Delegate(TFunctor* pCallback)
:m_pInvoker(NULL)
{
FunctorInvoker
m_pInvoker = FunctorInvoker
}
TReturn operator() (TArgument args)
{
return m_pInvoker(args);
}
//implementations
private:
InvokerType m_pInvoker;
};
delegate 本身就是一個函數(shù)對象,針對C++里3類函數(shù)提供了3個構(gòu)造函數(shù),每個構(gòu)造函數(shù)的實現(xiàn)分別用到了一個輔助類別,分別是Invoker(用于全局函數(shù)或者類的靜態(tài)函數(shù)),MemberInvoker(用于類成員函數(shù)),F(xiàn)unctorInvoker(用于functor) ,這三個輔助類別主要用于在編譯時保存函數(shù)類型,對象類型等信息。實現(xiàn)如下:
template
struct Invoker
{
typedef TReturn (*Method)(TArgument args);
static TReturn Invoke(TArgument args)
{
return m_pCallback(args);
}
static void Bind(Method pCallback)
{
m_pCallback = pCallback;
}
private:
static Method m_pCallback;
};
template
typename Invoker
template
struct MemberInvoker
{
typedef TReturn (TObject::*MemberMethod)(TArgument);
static TReturn Invoke(TArgument args)
{
return (m_pObject->*m_pCallback)(args);
}
static void Bind(TObject* pObject,MemberMethod pCallback)
{
m_pObject = pObject;
m_pCallback = pCallback;
}
private:
static TObject* m_pObject;
static MemberMethod m_pCallback;
};
template
TObject* MemberInvoker
template
typename MemberInvoker
template
struct FunctorInvoker
{
typedef TFunctor* FunctorMethod;
static TReturn Invoke(TArgument args)
{
return m_pCallback(args);
}
static void Bind(FunctorMethod pCallback)
{
m_pCallback = pCallback;
}
private:
static FunctorMethod m_pCallback;
};
template
typename FunctorInvoker
至此,一個完整的delegate實現(xiàn)完畢,我們可以用它來實現(xiàn)event 了。
event實現(xiàn)如下,為了實現(xiàn)多播用std::list保存多個deledate:
template< class TReturn, class TArgument>
class Event
{
public:
typedef TReturn ReturnValue;
typedef TArgument EventArgs;
typedef Delegate
public:
Event(){}
virtual ~Event(){}
public:
ReturnValue GetReturnValue(const EventHandler& rhs )
{
return m_ReturnValue[rhs];
}
ReturnValue operator() (EventArgs/* const& */rhs)
{
ReturnValue RetValue;
for (std::list
{
RetValue = (*i)(rhs);
m_ReturnValue[(*i)] = RetValue;
}
return RetValue;
}
Event& operator+= ( EventHandler/* const& */rhs )
{
m_Handler.push_back(rhs);
return *this;
}
Event& operator-= ( EventHandler/* const& */rhs )
{
m_Handler.remove(rhs);
return *this;
}
private:
std::list
std::map
};
event重載了+=, -=操作符,使用上完全跟C#原生的event操作基本一樣。event實際上就是一個多播delegate,如果不需要多播,直接使用delegate就可以了。
目前的實現(xiàn)還有一些小問題:
1.目前event不支持void返回類型,其實只要寫一個event
2. 由于C++語言對模板的一些限制,不得以在頭文件中定義了一些靜態(tài)成員變量,所以當在多個.cpp文件中包含這個頭文件時會有鏈接錯誤,VC下可以使用_declspec(selectany)解決這個問題,別的編譯器我就不知道了。

