在C++中实现事件(委托)(续)

在上文  在C++中实现事件(委托)  中我们实现的C#里委托方式的事件处理, 虽然使用很方便,但是感觉似乎少了一点C#的味道, 下面我们尝试把它改成真正的C#版。

其实要改成真正的C#版,我们主要要做2件事, 一是吧CEventHandler放到外面,可以让外部直接构造, 二是实现operator +=和operator -=, 下面是我的实现代码:
#pragma once

#include <functional>
#include <algorithm>
#include <vector>
#include <assert.h>

namespace  Common
{
    typedef  void * cookie_type;

    template<typename TR, typename T1, typename T2>
     class  CEventHandler 
    {
     public :
        typedef TR return_type;
        typedef T1 first_type;
        typedef T2 second_type;

        typedef std::function<return_type (first_type, second_type)> handler_type;

        CEventHandler( const  CEventHandler& h)
        {
            _handler = h._handler;
            assert(_handler != nullptr);
        }

        CEventHandler(handler_type h)
        {
            _handler = h;
            assert(_handler != nullptr);
        }

        template<typename class_type, typename class_fun>
        CEventHandler(class_type* pThis, class_fun object_function)
        {
             using  namespace  std::placeholders;
            _handler = std::bind(object_function, pThis, _1, _2);
            assert(_handler != nullptr);
        }

        return_type  operator ()(first_type p1, second_type p2)
        {
            return_type ret = return_type();
            assert(_handler != nullptr);
             if (_handler != nullptr) ret = _handler(p1, p2);
             return  ret;
        }

        handler_type _handler;
    };

    template<typename EventHandler>
     class  CEvent
    {
     public :
        typedef EventHandler event_handler_type;
        typedef typename event_handler_type::return_type return_type;
        typedef typename event_handler_type::first_type first_type;
        typedef typename event_handler_type::second_type second_type;
        typedef typename event_handler_type::handler_type handler_type;

        ~CEvent()
        {
            Clear();
        }

        return_type  operator ()(first_type p1, second_type p2)
        {
            return_type ret = return_type();
            size_t size = _handlers.size();
             for (auto p : _handlers)
            {
                ret = p-> operator ()(p1, p2);
            }
             return  ret;
        }

        cookie_type AddHandler( const  event_handler_type& h)
        {
            event_handler_type*p =  new (nothrow)  event_handler_type(h);
             if (p != nullptr) _handlers.push_back(p);
             return  (cookie_type)p;
        }

         void  RemoveHandler(cookie_type cookie)
        {
            event_handler_type* p = (event_handler_type*)cookie;

            auto itr = std::find(_handlers.begin(), _handlers.end(), p);
             if (itr != _handlers.end())
            {
                _handlers.erase(itr);
                delete p;
            }
             else
            {
                assert( false );
            }
        }

        cookie_type  operator  += ( const  event_handler_type& pHandler)
        {
             return  AddHandler(pHandler);
        }

         void  operator  -= (cookie_type cookie)
        {
            RemoveHandler(cookie);
        }

         void  Clear()
        {
             if (!_handlers.empty())
            {
                 int  n = _handlers.size();
                std::for_each(_handlers.begin(), _handlers.end(), [](event_handler_type* p)
                { 
                    assert(p != nullptr);
                    delete p;
                });
                _handlers.clear();        
            }
        }

     private :
        std::vector<event_handler_type*> _handlers;
    };

// Common

然后我们就可以这样使用了:
//  EventTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <iostream>
#include "event2.h"

using  namespace  std;

class  CObjectX 
{

};

class  CClickEventArgs:  public  CObjectX
{

};


class  CButton:  public  CObjectX
{
public :
     void  FireClick()
    {
        CClickEventArgs args;
        OnClicked( this , args);
    }

    typedef Common::CEventHandler< int , CObjectX*, CClickEventArgs&> ButtonClickEventHandler;
    Common::CEvent<ButtonClickEventHandler> OnClicked;
};


class  CMyClass 
{
public :
     int  OnBtuttonClicked(CObjectX* pButton, CClickEventArgs& args)
    {
        cout << "CMyClass: Receive button clicked event" << endl;
         return  1;
    }
};

int  OnBtuttonClicked_C_fun(CObjectX* pButton, CClickEventArgs& args)
{
    cout << "C Style Function: Receive button clicked event" << endl;
     return  1;
}


class  CMyFunObj
{
public :
     int  operator ()(CObjectX* pButton, CClickEventArgs& args)
    {
        cout << "Functor: Receive button clicked event" << endl;
         return  1;    
    }
};

int  _tmain( int  argc, _TCHAR* argv[])
{
    CButton btn;

    CMyClass obj;
    Common::cookie_type c1 = btn.OnClicked += CButton::ButtonClickEventHandler(&obj, &CMyClass::OnBtuttonClicked);

    Common::cookie_type c2 = btn.OnClicked += CButton::ButtonClickEventHandler(OnBtuttonClicked_C_fun);

    CMyFunObj functor;
    Common::cookie_type c3 = btn.OnClicked += CButton::ButtonClickEventHandler(functor);

    btn.FireClick();

    btn.OnClicked -= c2;

    std::cout << endl;

    btn.FireClick();

    system("pause");

     return  0;
}

怎么样,是不是感觉和C#一样了 !


最后,我们比较一下2种实现方式:
第一种方法把委托函数类型封装起来了,对外部来说是透明的, 使用起来更简单。
第二种方式把委托函数的类型暴露了出来, 适用于 事件处理函数类型各异, 比较强调事件处理函数类型的场合。

其实对于C++来说,个人觉得还是第一种方式更合理, 不知道大家怎么看?

 

 注: 如果你不想用C++11的新特性或是你手头的编译器不支持C++11, 下面是一种不借助function和bind的实现方式,

    直接用下面的CEventHandler替代上面的就可以了。

 

 

ExpandedBlockStart.gif 一种不借助C++11 function和bind的实现方式
template<typename TR, typename T1, typename T2>
     class CEventHandler
    {
     public:
        typedef TR return_type;
        typedef T1 first_type;
        typedef T2 second_type;

     private:
         class CFunctionBase 
        {
         public:
             virtual return_type Invoke(first_type p1, second_type p2) =  0;
             virtual CFunctionBase* Clone() =  0;
             virtual ~CFunctionBase() { }
        };

        template<typename TFunType>
         class CFunction:  public CFunctionBase
        {
         public:
            CFunction( const TFunType& f): _f(f) { }
             virtual return_type Invoke(first_type p1, second_type p2)
            {
                 return _f(p1, p2);
            }
             virtual CFunctionBase* Clone()
            {
                 return  new CFunction( this->_f);
            }

         private:
            TFunType _f;
        };

        template<typename TClassPtr, typename TMemFunType>
         class CClassMemFun:  public CFunctionBase
        {
         public:
            CClassMemFun(TClassPtr pObj,  const TMemFunType& f): _pObj(pObj), _pMemFun(f) { }
             virtual return_type Invoke(first_type p1, second_type p2)
            {
                 return ((*_pObj).*_pMemFun)(p1, p2);
            }
             virtual CFunctionBase* Clone()
            {
                 return  new CClassMemFun( this->_pObj,  this->_pMemFun);
            }

         private:
            TClassPtr _pObj;
            TMemFunType _pMemFun;
        };

     public:
        template<typename TFunType>
        CEventHandler( const TFunType& f): _pFun( new CFunction<TFunType>(f)) { }

        template<typename TClassPtr, typename TMemFunType>
        CEventHandler(TClassPtr pObj, TMemFunType pFun): _pFun( new CClassMemFun<TClassPtr, TMemFunType>(pObj, pFun)) { }

        CEventHandler( const CEventHandler& f)
        {
            _pFun = f._pFun->Clone(); 
        }

        ~CEventHandler()
        {
            delete _pFun;
        }

        CEventHandler&  operator = ( const CEventHandler& f)
        {
             if( this != &f)
            {
                delete _pFun;
                _pFun = f._pFun->Clone(); 
            }

             return * this;
        }

        return_type  operator()(first_type p1, second_type p2)
        {
            return_type ret = return_type();
             if(_pFun != nullptr)
            {
                _pFun->Invoke(p1, p2);
            }
             else
            {
                assert( false);
            }

             return ret;
        }

     private:
        CFunctionBase* _pFun;

转载于:https://www.cnblogs.com/weiym/archive/2013/01/31/2887477.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值