青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

C++中實現(xiàn)回調(diào)機制的幾種方式一文中,我們提到了實現(xiàn)回調(diào)的三種方式(C風格的回調(diào)函數(shù), Sink方式和Delegate方式)。在面向?qū)ο箝_發(fā)中,delegate的方式是最靈活和方便的,因此很早就有人用復(fù)雜的模板去模擬(有興趣的話可以看這里這里),總之是實現(xiàn)起來很復(fù)雜。但是現(xiàn)在借助C++11的functionbind, 我們可以很方便的去實現(xiàn)。下面是我自己的一種實現(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;
    };
}

大概實現(xiàn)思想是我們通過一個內(nèi)置的CEventHandler 類來封裝處理函數(shù),我們可以通過AddHandler來添加事件處理函數(shù),添加時會返回一個Cookie,我們可以通過該Cookie來RemoveHandler, 下面是測試代碼:
#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;
}

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


 可以看到, 我們在普通C函數(shù), 類成員函數(shù)和仿函數(shù)(functor)中都測試通過。

另外對于事件函數(shù)返回值為void的情況,會編譯出錯,我們需要偏特化一下:
    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;
    };

最后談一下在寫這個代碼中遇到的問題:
(1)不知道你能不能發(fā)現(xiàn)下面代碼的問題, 我在寫代碼時就栽在這里了:
     vector<int*>  v;
    int* p1 = new int(1);
    v.push_back(p1);
    int* p2 = new int(2);
    v.push_back(p2);
 
    //嘗試刪除所有值為p1的項
    //由該代碼想到=>v.erase(std::remove(v.begin(), v.end(), p1), v.end());
    //錯誤代碼:
    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);
太不方便了, 不知道大家有沒有好的方法。

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

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

這里保持bind在外邊可以保留靈活性,比如把三個參數(shù)的事件處理函數(shù)加上一個默認參數(shù)綁定到兩個參數(shù)的事件上。另外把Event定義為
template<class A1 = NullT, class A2 = NullT,...>
這樣的形式,利用偏特化,就可以支持任意個數(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ù)  更多評論
  
# re: 在C++中實現(xiàn)事件(委托)
2013-01-31 17:36 | Richard Wei
@lierlier
多謝指點,感覺你的實現(xiàn)方式對外界比較靈活,性能也比較高。
而我的實現(xiàn)更強調(diào)封裝,適合于在某個框架中使用。  回復(fù)  更多評論
  
# re: 在C++中實現(xiàn)事件(委托)
2013-02-01 16:49 | zdhsoft
如果我直接使用bind,是不是明顯比你的靈活多了?初步看了一下,樓主只是在bind上加了一個外殼封裝而已。真正委托的實現(xiàn),還是交給了bind  回復(fù)  更多評論
  
# re: 在C++中實現(xiàn)事件(委托)
2013-02-01 17:05 | Richard Wei
@zdhsoft
恩,本身就是借助c++11的 function和bind進行封裝  回復(fù)  更多評論
  
# re: 在C++中實現(xiàn)事件(委托)
2013-02-07 13:32 | Jeff Chen
我有兩個問題:
1、為何不使用boost的signal呢?
2、您的方案與signal相比,有哪些優(yōu)點,哪些缺點呢?  回復(fù)  更多評論
  
# re: 在C++中實現(xiàn)事件(委托)
2013-02-07 17:03 | Richard Wei
@Jeff Chen
慚愧, 沒研究過boost。
可能優(yōu)點就是簡單,可以自己掌控吧,實際上好多公司是禁用boost的。  回復(fù)  更多評論
  
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美成人午夜激情视频| 欧美怡红院视频一区二区三区| 一区二区三区精品视频在线观看| 欧美一区不卡| 国产亚洲一本大道中文在线| 久久国产精品色婷婷| 欧美国产精品人人做人人爱| 中国亚洲黄色| 在线观看国产精品网站| 欧美精品一区二区三区高清aⅴ| 亚洲欧美日韩国产| 国产一区日韩欧美| 欧美日一区二区三区在线观看国产免| 亚洲人体大胆视频| 亚洲国产一区二区三区高清| 久久久青草婷婷精品综合日韩| 久久久国产精品一区二区中文| 国产精品高清在线观看| 亚洲在线视频免费观看| 国产精品99久久久久久白浆小说| 免费成人黄色片| 亚洲精品免费在线播放| 亚洲福利视频网站| 久久久久91| 亚洲精品在线视频观看| 久久久www成人免费无遮挡大片| 亚洲毛片网站| 黑人极品videos精品欧美裸| 国产精品v欧美精品v日韩| 性欧美xxxx视频在线观看| 一区二区激情| 欧美深夜福利| 久久精品亚洲热| 一区二区三区波多野结衣在线观看| 亚洲精品中文字| 99这里只有精品| 欧美在线视频免费| 欧美日韩精品免费看| 欧美.日韩.国产.一区.二区| 国产午夜精品美女毛片视频| 欧美日韩国产欧美日美国产精品| 欧美在线国产精品| 宅男噜噜噜66一区二区| 欧美日韩综合精品| 久久成人18免费网站| 极品中文字幕一区| 小黄鸭精品aⅴ导航网站入口| 欧美伊人久久| 狠狠色狠色综合曰曰| 亚洲高清av| 国产日本亚洲高清| 久久久久久亚洲精品杨幂换脸| 看片网站欧美日韩| 99这里只有精品| 久久人人超碰| 国产一区二区三区高清在线观看| 精品999网站| 久久一区亚洲| 亚洲成人在线视频播放 | 中国成人黄色视屏| 国产在线观看精品一区二区三区 | 亚洲激情一区二区| 亚洲国产精品一区二区三区| 老司机午夜精品视频在线观看| 午夜亚洲一区| 欧美在线视频二区| 久久久蜜桃一区二区人| 久久免费视频在线观看| 麻豆亚洲精品| 99精品欧美一区二区三区| 久久精品2019中文字幕| 亚洲国产高潮在线观看| 国产精品一区二区你懂得| 欧美大片免费| 亚洲人屁股眼子交8| 午夜久久tv| 欧美在线观看一区二区| 国产精品久久久久久久午夜片| 亚洲精品视频啊美女在线直播| 欧美在线观看视频一区二区| 久久婷婷亚洲| 久久福利一区| 在线观看成人网| 日韩视频一区二区三区在线播放免费观看| 久久久午夜电影| 欧美电影资源| 欧美午夜精品一区| 亚洲欧美清纯在线制服| 久热这里只精品99re8久| 久久综合一区二区| 国产精品v片在线观看不卡 | 亚洲调教视频在线观看| 蜜臀av一级做a爰片久久 | 国产精品久久久久久av下载红粉| 欧美 日韩 国产 一区| 免费在线成人av| 亚洲精选视频免费看| 亚洲午夜免费福利视频| 欧美va天堂| 欧美日韩在线一二三| 国产人成一区二区三区影院| 亚洲国产天堂久久综合| 麻豆91精品91久久久的内涵| 亚洲人成人一区二区在线观看| 亚洲欧美日韩精品久久| 国产精品s色| 这里只有精品丝袜| 美女主播精品视频一二三四| 亚洲第一精品夜夜躁人人爽| 国产精品一区二区三区四区五区| 在线观看视频一区二区| 久久精品国产一区二区三区| 一区二区三区视频在线观看 | 欧美精品久久久久a| 久久久久亚洲综合| 国产色产综合产在线视频| 亚洲永久在线| aa级大片欧美| 欧美日韩一区二区三区在线视频| 亚洲美女一区| 亚洲成人在线| 夜夜狂射影院欧美极品| 一区二区三区在线观看视频| 亚洲天堂av高清| 亚洲人成人99网站| 欧美在线在线| 亚洲毛片在线| 亚洲精品免费电影| 亚洲综合日韩在线| 一本大道久久a久久精品综合| 久久精品国产久精国产爱| 亚洲女性裸体视频| 欧美日韩网站| 亚洲精品一线二线三线无人区| 亚洲精品久久久久久久久| 看欧美日韩国产| 欧美一区二区三区在线看| 日韩亚洲一区二区| 久久精品国产99精品国产亚洲性色| 亚洲一二三区视频在线观看| 欧美一乱一性一交一视频| 亚洲天堂av在线免费| 99视频精品全国免费| 欧美激情1区| 一本色道久久加勒比88综合| 欧美怡红院视频一区二区三区| 在线亚洲高清视频| 欧美日韩免费| 制服丝袜亚洲播放| 午夜亚洲性色福利视频| 欧美日韩综合久久| 亚洲视频一二三| 亚洲自啪免费| 国产色视频一区| 久久国产精品久久久久久| 蜜桃精品久久久久久久免费影院| 国产一区二区三区久久| 久久成人18免费观看| 欧美jizzhd精品欧美巨大免费| 亚洲黄一区二区| 欧美日韩成人综合在线一区二区 | 欧美成人一区二区三区片免费| 亚洲精品乱码久久久久久蜜桃91| 亚洲高清资源综合久久精品| 欧美成人激情视频免费观看| 麻豆av一区二区三区| 欧美77777| 亚洲伦理在线观看| 亚洲综合色激情五月| 国产精品夜夜嗨| 久久久久久久激情视频| 欧美成va人片在线观看| 亚洲精品国精品久久99热一 | 老牛国产精品一区的观看方式| 欧美大片免费久久精品三p| 99re8这里有精品热视频免费 | 亚洲深夜激情| 久久婷婷影院| 亚洲视频电影在线| 国产在线观看91精品一区| 欧美激情精品久久久久久蜜臀 | 免费试看一区| 一本色道久久88综合日韩精品| 欧美一级播放| 亚洲乱码国产乱码精品精天堂 | 亚洲国产欧美一区| 欧美视频一区二区三区| 久久国内精品自在自线400部| 亚洲欧洲日产国码二区| 亚洲欧洲99久久| 亚洲国产综合视频在线观看| 欧美日韩亚洲一区二区三区| 久久精品国产欧美激情| 欧美激情一区二区| 亚欧美中日韩视频| 欧美激情视频一区二区三区在线播放 | 欧美日韩亚洲综合在线| 亚洲第一精品夜夜躁人人爽| 久久精品亚洲精品| 欧美激情一区二区三区蜜桃视频|