• <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>
            cyt
            發(fā)現(xiàn)原來已經(jīng)有兩個多月沒有寫blog了。近來工作都很忙,回到家都懶懶的不想動。雖然工作上做了很多有趣的東西,但畢竟有版權(quán)保護(hù),在公司做的工作不能直接寫在blog上,也要抽些時間整理一下才能放上來。
            ??? 今天在 www.codeproject.com 上又發(fā)現(xiàn)比較好玩的東西:http://www.codeproject.com/cpp/acfdelegate.asp
            或者去 http://acfproj.sourceforge.net/.

            ??? 作者甚是好耐心開發(fā)了一套和C#用法差不多的C++庫。當(dāng)然這里只是著重討論他的Delegate實(shí)現(xiàn)。其實(shí)Delegate也不是什么新技術(shù),正如下文有人提出的boost.singal (http://www.boost.org/doc/html/signals.html)、另外還有:

            Delegate - Extended Callback Library????http://callbackext.berlios.de
            Libsigc++?????????????????? http://libsigc.sourceforge.net
            libSigCX(對libSigC++的擴(kuò)展) http://libsigx.sourceforge.net
            sigslot??????????????????????? http://sigslot.sourceforge.net/
            slotsig??????????????????????? http://slotsig.sourceforge.net/
            ????????????? 這個和上面的sigslot不是同一個東西,作者起的名字……一點(diǎn)新意都沒有,而且作者還提供了一個性能比較的benchmark,比較了qt、boost、libsigc++和自己,結(jié)果可以看這里:http://slotsig.sourceforge.net/doc/benchmarks.html
            作者還說:The sigslot library has not been benchmarked, because it provides too less features than the others。當(dāng)然Qt用的是完全另外一套東西,通過預(yù)編譯實(shí)現(xiàn)的signal / slot,個人覺得完全沒有可比性,當(dāng)然Qt的實(shí)現(xiàn)方法也是我個人所討厭的,非要多一個預(yù)編譯器出來,開發(fā)時候極為不爽。

            ??? 找回以前的代碼,我在2002年的時候原來也已經(jīng)實(shí)現(xiàn)過一個signal / slot,不過在slotsig作者眼中也是provides too less features。不過當(dāng)然是自己夠用就行了。之所以要“重復(fù)開發(fā)”,原因之一是以上的很多l(xiāng)ib不支持VC6,當(dāng)時我還在用破破爛爛的VC6;一方面我也不愿意自己的project里面塞一大堆lib,特別是boost的,龐大的嚇人;一方面也就是自己能力的鍛煉;還有一方面就是發(fā)現(xiàn)有些lib里面的實(shí)現(xiàn)用了些trick(例如用byte array保存指針),這也是個人不喜歡的東西。

            ??? 其實(shí)實(shí)現(xiàn)的原理很簡單,先以一個簡單的例子說明:
            假設(shè)需要處理?? int??? f(int a);的singl / slot,如果單是函數(shù)指針,那就太簡單了,slot就是函數(shù)指針,singal就是函數(shù)指針的數(shù)組。但現(xiàn)在還要加上對象的成員函數(shù),于是就會想到把這兩種東西合并起來,但從外面看有相同的接口。其實(shí)function object就是這樣一種東西,不過function object只能在編譯時期實(shí)現(xiàn)普通函數(shù)和成員函數(shù)接口統(tǒng)一,但現(xiàn)在需要在運(yùn)行時期,很自然就會想到了虛函數(shù):
            struct?slot1base
            ?? { virtual int fun(int a) = 0; };

            typedef? SmartPotint?? slot1;

            struct?singal1
            {
            ??? int emit(int a) {??? /*?call each slot in m_listSlot?*/ }
            ??? void?connect( slot1 s) { m_listSlot.push_back(s); }

            protected:
            ??? std::list?? m_listSlot;
            };
            其中SmartPoint就是帶引用計數(shù)的智能指針,很多實(shí)現(xiàn)的庫,隨便選一個吧。
            很明顯,我們現(xiàn)在就是需要一個singal1,然后往它里面的m_listSlot里面不斷放slot1base的子類。現(xiàn)在要做的事情,就是要把不同的形如 int f(int)樣式的函數(shù)調(diào)用(包括普通函數(shù)和成員函數(shù))統(tǒng)統(tǒng)轉(zhuǎn)換為slot1base的子類。于是就有很多子類出來了:

            struct slot1func : public slot1base
            {
            ?typedef int (* func)(int);
            ?
            ?slot1func(func p) : m_func(p) {}
            ?virtual int fun(int a) { return m_func(a); }
            private:
            ?func?m_func;
            };

            template
            struct slot1objfunc : public slot1base
            {
            ?typedef?int (obj::*func)(int);
            ?
            ?slot1objfunc(obj * p, func pF) : m_obj(p),m_pfunc(pF) {}
            ?virtual int fun(int a) { return (m_obj->*m_func)(a); }
            private:
            ?obj?*?m_obj;
            ?func?m_pfunc;
            };

            其實(shí)除了這兩種以外,還可以擴(kuò)展出更多的子類,例如能自動進(jìn)行函數(shù)參數(shù)的類型轉(zhuǎn)換的子類:
            struct slot1func_for_short : public slot1base
            {
            ?typedef?short (* func)(short);
            ?
            ?slot1func_for_short(func p) : m_func(p) {}
            ?virtual int fun(int a) { return m_func(a); }
            private:
            ?func?m_func;
            };
            當(dāng)然可以抽象為template
            template
            struct slot1func_for_other : public slot1base
            {
            ?typedef?R2 (* func)(A2);
            ?
            ?slot1func_for_other(func p) : m_func(p) {}
            ?virtual int fun(int a) { return m_func(a); }
            private:
            ?func?m_func;
            };
            同樣還應(yīng)該有for object function的版本……
            除了這些,還可以有更多的,例如處理object的const函數(shù)的;處理本來沒有返回值,每次需要虛擬一個返回值的函數(shù);參數(shù)個數(shù)不一致,需要另外bind參數(shù)的……

            現(xiàn)在有了很多子類以后,我們當(dāng)然不希望要記著這么多子類的名稱,希望使用的時候只通過同一個接口就可以生成我們所需要的slot1,這時候就是經(jīng)典的template function出場了:
            slot1?slot(int (*func)(int))
            ?{ return slot1( new slot1func(func) ); }
            template
            ?slot2?slot(obj * p, int (obj::*func)(int) )
            ??{ return slot1( new slot1objfunc(p,func) ); }
            template
            ?slot2?slot( R2 (*func)(A2) )
            ??{ return slot1( new slot1func_for_other(func) ); }

            應(yīng)用的時候就可以:
            int??? func1(int a) { ..... }
            struct MyObj {??? int func2(int a) { .... } };

            MyObj???? obj;

            signal1????? onButtonClick;
            onButtonClick.connect( slot( func1) );
            onButtonClick.connect( slot( *obj, func2) );
            return onButtonClick.emit( 100 );

            原理很簡單吧,但這個只是int func(int)格式的slot1,如果參數(shù)不是int,返回值不是int呢?簡單,把上面的東西變成模版就行了。
            template
            struct?slot1base
            ?? { virtual?R fun(A1 a) = 0; };

            template
            struct slot1 : public? SmartPotint >?? {}

            template
            struct?singal1
            {
            ????R emit(A a) {??? /*?call each slot in m_listSlot?*/ }
            ??? void?connect( slot1 s) { m_listSlot.push_back(s); }

            protected:
            ??? std::list >?? m_listSlot;
            };

            ……后面的子類也作相應(yīng)的處理。

            原理是簡單,不過要做一個完整的機(jī)制還要考慮更多的東西:
            1、singal 和slot之間一般是“多對多”的關(guān)系,所以應(yīng)該slot里面也有singal的列表,以方便雙向查找。
            2、多線程下的重入問題,如何加上鎖,是需要仔細(xì)考慮的。
            3、當(dāng)一個singal里面包含多個slot的時候,那個返回值的處理,這個真的是多種多樣了:
            ???? 只要其中一個的返回值;所有返回值記錄在數(shù)組里面;當(dāng)其中一個返回值是特定值時候不繼續(xù)后面的slot……
            ???? 所以一般都會在singal1的模版參數(shù)中增加一個TMarshal的類來處理返回值:
            ???? template
            ???? struct singal1
            ???? {
            ???????? R emit(A1 a)
            ???????? {
            ??????????? typeMarsh?marsh;
            ??????????? /* for each item in m_listSlot*/
            ??????????? {
            ???????????????? if (! marsh.toContinue( (*it)->fun(a)))
            ????????????????????? break;
            ??????????? }
            ??????????? return marsh.value();
            ???????? }
            ??? };
            ?而一個簡單TMarshal可以是這樣:
            ?template
            ??class TMarshal
            ??{
            ??public:
            ???TMarshal(void) : m_saveValue() {}
            ???static typeReturn?defaultValue(void) { return typeReturn(); }
            ???typeReturn?value(void) { return m_saveValue; }
            ???bool?toContinue(const typeReturn & val)
            ????{?m_saveValue = val;?return true;?}
            ??protected:
            ???typeReturn?m_saveValue;
            ??};
            4、現(xiàn)在只是討論了一個參數(shù)的情況,多個參數(shù)的呢?好辦,copy/paste一個參數(shù)的,加上多個參數(shù)就是了,例如:
            ?template
            ??struct slot2base
            ???{? virtual R fun(A1 a1, A2 a2) = 0; };
            ?不過的確是很煩人的工作,于是很多l(xiāng)ib都是通過宏來實(shí)現(xiàn),例如:
            ?一個 signalslot.imp的文件里面:
            ?template
            ??struct?SLOTBASENAME
            ???{?virtual R fun(FUNC_ARGS) = 0; };
            ?……
            ?而singalslot.h里面就定義:
            ?#define TEMPLATE_ARGS?typename A1
            ?#define FUNC_ARGS??A1 a1
            ?#define SLOTBASENAME?slot1base
            ?#include "signalslot.imp"
            ?
            ?#define TEMPLATE_ARGS?typename A1,typename A2
            ?#define FUNC_ARGS??A1 a1, A2 a2
            ?#define SLOTBASENAME?slot2base
            ?#include "signalslot.imp"
            ?……
            ?
            ?更有甚者,直接用perl來生成.h文件……
            5、需要更多的接口,方便使用,例如slot的查找、刪除、比較之類的。

            posted on 2005-10-08 14:50 cyt 閱讀(5406) 評論(2)  編輯 收藏 引用
            Comments
            • # re: 我自己的signal / slot實(shí)現(xiàn)
              joyfire
              Posted @ 2005-11-26 00:24
              引用了這篇文章,可是找補(bǔ)到trackback:(  回復(fù)  更多評論   
            • # re: 我自己的signal / slot實(shí)現(xiàn)
              你好!
              Posted @ 2007-06-15 09:02
              你好, 看了你的文章感覺你好厲害得說!
              我不是專門研究程序的人,可現(xiàn)在我有點(diǎn)小困難,你肯定知道怎么解決
              你的文章里說:
              而singalslot.h里面就定義:
              #define TEMPLATE_ARGS typename A1
              #define FUNC_ARGS A1 a1
              #define SLOTBASENAME slot1base
              #include "signalslot.imp"

              #define TEMPLATE_ARGS typename A1,typename A2
              #define FUNC_ARGS A1 a1, A2 a2
              #define SLOTBASENAME slot2base
              #include "signalslot.imp"
              ……
              我運(yùn)行程序時候就缺少這個文件,一直在尋找這個頭文件,你能幫忙寫給我嗎?
              我的QQ346183499,全天再線
              謝謝了!  回復(fù)  更多評論   

            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


             
            狠色狠色狠狠色综合久久| 国产精品久久久香蕉| 青青草国产精品久久久久| 精品久久久久久亚洲| 久久播电影网| 久久人人爽人人爽人人AV东京热 | 久久国产综合精品五月天| 久久久久九九精品影院| 精品无码久久久久国产动漫3d| 久久国产色AV免费观看| 久久久久无码精品| 久久国产高清字幕中文| 思思久久精品在热线热| 观看 国产综合久久久久鬼色 欧美 亚洲 一区二区 | 久久99国产精品久久99果冻传媒 | 亚洲国产精品成人久久| 久久国产成人亚洲精品影院| 亚洲精品无码久久久影院相关影片 | 久久精品国产免费观看| 精品久久久久久99人妻| 久久99国产精一区二区三区 | 97久久国产亚洲精品超碰热| 婷婷久久综合| 久久播电影网| 久久国产免费直播| 久久国产精品99久久久久久老狼| 亚洲va久久久噜噜噜久久| 久久狠狠一本精品综合网| 国产精品成人久久久久三级午夜电影| 精品国产乱码久久久久软件| 亚洲精品NV久久久久久久久久| 草草久久久无码国产专区| 99久久免费国产精精品| 久久久久久国产精品免费无码| 亚洲午夜久久久影院| 亚洲色大成网站www久久九| 亚洲伊人久久精品影院| 婷婷久久香蕉五月综合加勒比| 亚洲AV无码一区东京热久久| 少妇无套内谢久久久久| 久久精品国产亚洲AV蜜臀色欲 |