• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            C++中實(shí)現(xiàn)回調(diào)機(jī)制的幾種方式一文中,我們提到了實(shí)現(xiàn)回調(diào)的三種方式(C風(fēng)格的回調(diào)函數(shù), Sink方式和Delegate方式)。在面向?qū)ο箝_(kāi)發(fā)中,delegate的方式是最靈活和方便的,因此很早就有人用復(fù)雜的模板去模擬(有興趣的話可以看這里這里),總之是實(shí)現(xiàn)起來(lái)很復(fù)雜。但是現(xiàn)在借助C++11的functionbind, 我們可以很方便的去實(shí)現(xiàn)。下面是我自己的一種實(shí)現(xiàn)方式:
              namespace Common
            {
                typedef void* cookie_type;

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

                    typedef std::function<return_type (first_type, second_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(size_t i=0; i<size; ++i)
                        {
                            ret = _handlers[i]->operator()(p1, p2);
                        }
                        return ret;
                    }

                    cookie_type AddHandler(std::function<return_type (first_type, second_type)> h)
                    {
                        CEventHandler*p = new(nothrow)  CEventHandler(h);
                        if(p != nullptr) _handlers.push_back(p);
                        return (cookie_type)p;
                    }

                    template<typename class_type, typename class_fun>
                    cookie_type AddHandler(class_type* pThis, class_fun f)
                    {
                        CEventHandler* p = new(nothrow) CEventHandler(pThis, f);
                        if(p != nullptr) _handlers.push_back(p);
                        return (cookie_type)p;
                    }

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

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

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

                private:
                    class CEventHandler 
                    {
                    public:
                        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;
                    };


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

            大概實(shí)現(xiàn)思想是我們通過(guò)一個(gè)內(nèi)置的CEventHandler 類來(lái)封裝處理函數(shù),我們可以通過(guò)AddHandler來(lái)添加事件處理函數(shù),添加時(shí)會(huì)返回一個(gè)Cookie,我們可以通過(guò)該Cookie來(lái)RemoveHandler, 下面是測(cè)試代碼:
            #include "stdafx.h"
            #include <iostream>
            #include "event1.h"

            using namespace std;

            class CObjectX 
            {

            };

            class CClickEventArgs: public CObjectX
            {

            };


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

                Common::CEvent<int, CObjectX*, CClickEventArgs&> 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[])
            {
                using namespace std::placeholders;

                CButton btn;

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

                Common::cookie_type c2 = btn.OnClicked.AddHandler(OnBtuttonClicked_C_fun);

                CMyFunObj functor;
                Common::cookie_type c3 = btn.OnClicked.AddHandler(functor);

                btn.FireClick();


                btn.OnClicked.RemoveHandler(c2);

                std::cout << endl;


                btn.FireClick();

                system("pause");

                return 0;
            }

            以下是測(cè)試結(jié)果:


             可以看到, 我們?cè)谄胀–函數(shù), 類成員函數(shù)和仿函數(shù)(functor)中都測(cè)試通過(guò)。

            另外對(duì)于事件函數(shù)返回值為void的情況,會(huì)編譯出錯(cuò),我們需要偏特化一下:
                template< typename T1, typename T2>
                class CEvent<void, T1, T2>
                {
                public:
                    typedef void return_type;
                    typedef T1 first_type;
                    typedef T2 second_type;

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

                    ~CEvent()
                    {
                        Clear();
                    }

                    return_type operator()(first_type p1, second_type p2)
                    {
                        size_t size = _handlers.size();
                        for(size_t i=0; i<size; ++i)
                        {
                            _handlers[i]->operator()(p1, p2);
                        }
                    }

                    cookie_type AddHandler(std::function<return_type (first_type, second_type)> h)
                    {
                        CEventHandler*p = new(nothrow)  CEventHandler(h);
                        if(p != nullptr) _handlers.push_back(p);
                        return (cookie_type)p;
                    }

                    template<typename class_type, typename class_fun>
                    cookie_type AddHandler(class_type* pThis, class_fun f)
                    {
                        CEventHandler* p = new(nothrow) CEventHandler(pThis, f);
                        if(p != nullptr) _handlers.push_back(p);
                        return (cookie_type)p;
                    }

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

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

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

                private:
                    class CEventHandler 
                    {
                    public:
                        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)
                        {
                            assert(_handler != nullptr);
                            if(_handler != nullptr) _handler(p1, p2);
                        }

                        handler_type _handler;
                    };


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

            最后談一下在寫這個(gè)代碼中遇到的問(wèn)題:
            (1)不知道你能不能發(fā)現(xiàn)下面代碼的問(wèn)題, 我在寫代碼時(shí)就栽在這里了:
                 vector<int*>  v;
                int* p1 = new int(1);
                v.push_back(p1);
                int* p2 = new int(2);
                v.push_back(p2);
             
                //嘗試刪除所有值為p1的項(xiàng)
                //由該代碼想到=>v.erase(std::remove(v.begin(), v.end(), p1), v.end());
                //錯(cuò)誤代碼:
                auto itr = remove(v.begin(), v.end(), p1);
                for_each(itr, v.end(), [](int* p){delete p;});
                v.erase(itr, v.end());

               //正確代碼:
               v.erase(remove_if(v.begin(), v.end(), [](int*p)->bool {if(p==p1) {delete p; return true;} else return false}), v.end());

            (2)我們想把cookei_type放到類里面去, 類似這樣:
            1     template<typename TR, typename T1, typename T2>
            2     class CEvent
            3     {
            4     public:
            5         typedef TR return_type;
            6         typedef T1 first_type;
            7         typedef T2 second_type;
            8         typedef void* cookie_type;

            可發(fā)現(xiàn)要這樣使用:
            Common::CEvent<int, CObjectX*, CClickEventArgs&>::cookie_type c1 = btn.OnClicked.AddHandler(&obj, &CMyClass::OnBtuttonClicked);
            太不方便了, 不知道大家有沒(méi)有好的方法。

            注:上面的代碼還沒(méi)有經(jīng)過(guò)真正商業(yè)使用,如果有問(wèn)題歡迎指出。
            posted on 2013-01-31 14:16 Richard Wei 閱讀(10373) 評(píng)論(8)  編輯 收藏 引用 所屬分類: C++

            FeedBack:
            # re: 在C++中實(shí)現(xiàn)事件(委托)
            2013-01-31 14:45 | lierlier
            有返回值的事件是需要使用返回策略的,單純返回最后一個(gè)值由于回調(diào)綁定到事件順序是不確定的,所以實(shí)際上無(wú)意義  回復(fù)  更多評(píng)論
              
            # re: 在C++中實(shí)現(xiàn)事件(委托)
            2013-01-31 14:49 | Richard Wei
            @lierlier
            確實(shí), 所以.Net里的事件返回類型都都void。這里帶返回值的事件適用于只有一個(gè)函數(shù)綁定。  回復(fù)  更多評(píng)論
              
            # re: 在C++中實(shí)現(xiàn)事件(委托)
            2013-01-31 16:56 | lierlier
            如果不要求判斷函數(shù)是否已經(jīng)綁定過(guò)了,那么有個(gè)簡(jiǎn)單的做法

            這里保持bind在外邊可以保留靈活性,比如把三個(gè)參數(shù)的事件處理函數(shù)加上一個(gè)默認(rèn)參數(shù)綁定到兩個(gè)參數(shù)的事件上。另外把Event定義為
            template<class A1 = NullT, class A2 = NullT,...>
            這樣的形式,利用偏特化,就可以支持任意個(gè)數(shù)的事件參數(shù)

            代碼:
            #include <map>
            #include <functional>

            using namespace std;


            template<class Arg1, class Arg2>
            class Event
            {
            typedef void HandlerT(Arg1, Arg2);
            int m_handlerId;

            public:
            Event() : m_handlerId(0) {}

            template<class FuncT>
            int addHandler(FuncT func)
            {
            m_handlers.emplace(m_handlerId, forward<FuncT>(func));
            return m_handlerId++;
            }

            void removeHandler(int handlerId)
            {
            m_handlers.erase(handlerId);
            }

            void operator ()(Arg1 p1, Arg2 p2)
            {
            for ( const auto& i : m_handlers )
            i.second(p1, p2);
            }

            private:
            map<int, function<HandlerT>> m_handlers;
            };

            void f1(int, int)
            {
            printf("f1()\n");
            }

            struct F2
            {
            void f(int, int)
            {
            printf("f2()\n");
            }

            void operator ()(int, int)
            {
            printf("f3()\n");
            }
            };

            int _tmain(int argc, _TCHAR* argv[])
            {
            Event<int, int> e;

            int id = e.addHandler(f1);

            e.removeHandler(id);

            using namespace std::placeholders;

            F2 f2;

            e.addHandler(bind(&F2::f, f2, _1, _2));
            e.addHandler(bind(f2, _1, _2));

            e.addHandler([](int, int) {
            printf("f4()\n");
            });

            e(1, 2);

            return 0;
            }  回復(fù)  更多評(píng)論
              
            # re: 在C++中實(shí)現(xiàn)事件(委托)
            2013-01-31 17:36 | Richard Wei
            @lierlier
            多謝指點(diǎn),感覺(jué)你的實(shí)現(xiàn)方式對(duì)外界比較靈活,性能也比較高。
            而我的實(shí)現(xiàn)更強(qiáng)調(diào)封裝,適合于在某個(gè)框架中使用。  回復(fù)  更多評(píng)論
              
            # re: 在C++中實(shí)現(xiàn)事件(委托)
            2013-02-01 16:49 | zdhsoft
            如果我直接使用bind,是不是明顯比你的靈活多了?初步看了一下,樓主只是在bind上加了一個(gè)外殼封裝而已。真正委托的實(shí)現(xiàn),還是交給了bind  回復(fù)  更多評(píng)論
              
            # re: 在C++中實(shí)現(xiàn)事件(委托)
            2013-02-01 17:05 | Richard Wei
            @zdhsoft
            恩,本身就是借助c++11的 function和bind進(jìn)行封裝  回復(fù)  更多評(píng)論
              
            # re: 在C++中實(shí)現(xiàn)事件(委托)
            2013-02-07 13:32 | Jeff Chen
            我有兩個(gè)問(wèn)題:
            1、為何不使用boost的signal呢?
            2、您的方案與signal相比,有哪些優(yōu)點(diǎn),哪些缺點(diǎn)呢?  回復(fù)  更多評(píng)論
              
            # re: 在C++中實(shí)現(xiàn)事件(委托)
            2013-02-07 17:03 | Richard Wei
            @Jeff Chen
            慚愧, 沒(méi)研究過(guò)boost。
            可能優(yōu)點(diǎn)就是簡(jiǎn)單,可以自己掌控吧,實(shí)際上好多公司是禁用boost的。  回復(fù)  更多評(píng)論
              
            久久高清一级毛片| 精品蜜臀久久久久99网站| 岛国搬运www久久| 国产A级毛片久久久精品毛片| 久久本道综合久久伊人| 久久国产高清一区二区三区| 久久中文字幕精品| 伊人久久大香线蕉综合网站| 亚洲中文字幕久久精品无码喷水| 久久久久国产精品人妻| jizzjizz国产精品久久| 欧美日韩精品久久久久 | 欧美日韩精品久久久免费观看| 性欧美大战久久久久久久久| 久久精品中文字幕无码绿巨人| 久久精品人人做人人爽电影| 欧美久久亚洲精品| 久久综合色老色| 一级a性色生活片久久无少妇一级婬片免费放 | 国产亚洲色婷婷久久99精品91| 久久成人国产精品一区二区| 久久精品国产亚洲AV无码娇色 | 成人午夜精品久久久久久久小说| 四虎影视久久久免费| 99久久超碰中文字幕伊人| 亚洲日韩欧美一区久久久久我| 久久久精品免费国产四虎| 亚洲综合伊人久久大杳蕉| 久久久久亚洲AV无码专区桃色| AV无码久久久久不卡蜜桃| 亚洲欧美日韩久久精品第一区| 亚洲精品tv久久久久久久久久| 国产午夜精品理论片久久| 精品国产91久久久久久久| 国产精品美女久久久久| 99久久国产精品免费一区二区| 日韩美女18网站久久精品| 久久国产一片免费观看| 久久久99精品成人片中文字幕 | 国产欧美久久久精品影院| 国产精品99久久精品爆乳|