zoukankan      html  css  js  c++  java
  • 在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替代上面的就可以了。

    一种不借助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;

  • 相关阅读:
    C语言I作业12—学期总结
    C语言寒假大作战01
    C语言I作业12—学期总结
    C语言I博客作业11
    C语言I作业9
    C语言I博客作业08
    C语言I博客作业07
    C语言I博客作业05
    C语言I博客作业04
    C语言I博客作业03
  • 原文地址:https://www.cnblogs.com/weiym/p/2887477.html
Copyright © 2011-2022 走看看