C++實(shí)例:用C++模擬C#事件機(jī)制

字號(hào):

C#中的事件機(jī)制可以很方便的實(shí)現(xiàn)設(shè)計(jì)模式中的Observer模式,C#提供了delegate 和 event 來(lái)實(shí)現(xiàn)這種機(jī)制,實(shí)際上只要delagate就可以實(shí)現(xiàn)event效果,event語(yǔ)法完全沒必要,因?yàn)閐elegate是多播的。本文提供了一個(gè)C++版本的實(shí)現(xiàn),與C#原生的事件機(jī)制相比,只有一點(diǎn)不同,我實(shí)現(xiàn)的delegate是單播的(為了避免delegate 和 event 功能重復(fù)的問(wèn)題)。
    C# delegate 本質(zhì)上是一個(gè)函數(shù)的面向?qū)ο蟮姆庋b, 在C++語(yǔ)言中函數(shù)分好多種,包括 全局函數(shù),成員函數(shù),函數(shù)對(duì)象(即functor,雖然不是函數(shù),但因?yàn)樾袨橄窈瘮?shù),所以歸為函數(shù)一類),考試.大提示因此在C++里實(shí)現(xiàn)delegate的關(guān)鍵就是封裝上述3類函數(shù)的不同,對(duì)外提供一致的接口,先來(lái)看一下delegate的實(shí)現(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 本身就是一個(gè)函數(shù)對(duì)象,針對(duì)C++里3類函數(shù)提供了3個(gè)構(gòu)造函數(shù),每個(gè)構(gòu)造函數(shù)的實(shí)現(xiàn)分別用到了一個(gè)輔助類別,分別是Invoker(用于全局函數(shù)或者類的靜態(tài)函數(shù)),MemberInvoker(用于類成員函數(shù)),F(xiàn)unctorInvoker(用于functor) ,這三個(gè)輔助類別主要用于在編譯時(shí)保存函數(shù)類型,對(duì)象類型等信息。實(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;
    至此,一個(gè)完整的delegate實(shí)現(xiàn)完畢,我們可以用它來(lái)實(shí)現(xiàn)event 了。
    event實(shí)現(xiàn)如下,為了實(shí)現(xiàn)多播用std::list保存多個(gè)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實(shí)際上就是一個(gè)多播delegate,如果不需要多播,直接使用delegate就可以了。
    目前的實(shí)現(xiàn)還有一些小問(wèn)題:
    1.目前event不支持void返回類型,其實(shí)只要寫一個(gè)event偏特化就可,因?yàn)槲沂窃赩C6下寫的代碼,而VC6不支持模板偏特化
    2. 由于C++語(yǔ)言對(duì)模板的一些限制,不得以在頭文件中定義了一些靜態(tài)成員變量,所以當(dāng)在多個(gè).cpp文件中包含這個(gè)頭文件時(shí)會(huì)有鏈接錯(cuò)誤,VC下可以使用_declspec(selectany)解決這個(gè)問(wèn)題,別的編譯器我就不知道了。