<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type='text/xsl' href='http://flipcode.spaces.live.com/mmm2008-05-17_13.22/rsspretty.aspx?rssquery=en-US;http%3a%2f%2fflipcode.spaces.live.com%2fcategory%2f%e8%ae%be%e8%ae%a1%e6%a8%a1%e5%bc%8f%2ffeed.rss' version='1.0'?><rss version="2.0" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:msn="http://schemas.microsoft.com/msn/spaces/2005/rss" xmlns:live="http://schemas.microsoft.com/live/spaces/2006/rss" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:cf="http://www.microsoft.com/schemas/rss/core/2005" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>飘零风雨亭: 设计模式</title><description /><link>http://flipcode.spaces.live.com/?_c11_BlogPart_BlogPart=blogview&amp;_c=BlogPart&amp;partqs=cat%25E8%25AE%25BE%25E8%25AE%25A1%25E6%25A8%25A1%25E5%25BC%258F</link><language>en-US</language><pubDate>Mon, 23 Jun 2008 08:31:31 GMT</pubDate><lastBuildDate>Mon, 23 Jun 2008 08:31:31 GMT</lastBuildDate><generator>Microsoft Spaces v1.1</generator><docs>http://www.rssboard.org/rss-specification</docs><ttl>60</ttl><cf:parentRSS>http://flipcode.spaces.live.com/blog/feed.rss</cf:parentRSS><live:type>blogcategory</live:type><live:identity><live:id>-8189920746979949719</live:id><live:alias>flipcode</live:alias></live:identity><cf:listinfo><cf:group ns="http://schemas.microsoft.com/live/spaces/2006/rss" element="typelabel" label="Type" /><cf:group ns="http://schemas.microsoft.com/live/spaces/2006/rss" element="tag" label="Tag" /><cf:group element="category" label="Category" /><cf:sort element="pubDate" label="Date" data-type="date" default="true" /><cf:sort element="title" label="Title" data-type="string" /><cf:sort ns="http://purl.org/rss/1.0/modules/slash/" element="comments" label="Comments" data-type="number" /></cf:listinfo><item><title>类工厂</title><link>http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!122.entry</link><description>&lt;div&gt;&lt;strong&gt;&lt;/strong&gt; &lt;/div&gt;
&lt;div&gt;[注:]&lt;br&gt;这个类工厂是参考千里马肝所作,因为觉得很好就改了下拿来用:).希望他不要介意.&lt;br&gt;&lt;br&gt;// Factory.cpp : Defines the entry point for the application.&lt;br&gt;//&lt;br&gt;#include&amp;lt;windows.h&amp;gt;&lt;br&gt;#pragma warning(disable: 4786) &lt;/div&gt;
&lt;p&gt;
&lt;p&gt;#include&amp;lt;map&amp;gt;&lt;br&gt;#include&amp;lt;string&amp;gt;&lt;br&gt;#include&amp;lt;vector&amp;gt;
&lt;p&gt;//------------------------------------------------------&lt;br&gt;/*&lt;br&gt;**/&lt;br&gt;template&amp;lt; class base &amp;gt;&lt;br&gt;class Factory&lt;br&gt;{&lt;br&gt;static  Factory*             m_pInstance;&lt;br&gt;typedef base*                base_point;&lt;br&gt;typedef base_point           (*PFN_CREATOR)();
&lt;p&gt;std::map&amp;lt;std::string, PFN_CREATOR&amp;gt; m_mapStr2Func;&lt;br&gt;public:&lt;br&gt;base_point Create( const char* szName )&lt;br&gt;{&lt;br&gt;if( m_mapStr2Func.end() != m_mapStr2Func.find( szName ) )&lt;br&gt;{&lt;br&gt;return (*(m_mapStr2Func[szName]))();&lt;br&gt;}&lt;br&gt;return NULL;&lt;br&gt;}&lt;br&gt;static Factory* Instance()&lt;br&gt;{&lt;br&gt;if( !m_pInstance )&lt;br&gt;{&lt;br&gt;m_pInstance = new Factory;&lt;br&gt;}&lt;br&gt;return m_pInstance;&lt;br&gt;}&lt;br&gt;    void Register( const char* szID,  PFN_CREATOR pBase )&lt;br&gt;{&lt;br&gt;m_mapStr2Func[szID] = pBase;&lt;br&gt;}&lt;br&gt;    void UnRegister( const char* szID )&lt;br&gt;{&lt;br&gt;m_mapStr2Func.erase(szID);&lt;br&gt;}
&lt;p&gt;private: // prevent&lt;br&gt;const Factory&amp;amp; operator = (const Factory&amp;amp;);&lt;br&gt;Factory()               {}&lt;br&gt;Factory(Factory&amp;amp;)       {}
&lt;p&gt;};&lt;br&gt;template&amp;lt; class base &amp;gt;&lt;br&gt;Factory&amp;lt;base&amp;gt;* Factory&amp;lt;base&amp;gt;::m_pInstance = NULL;
&lt;p&gt;//------------------------------------------------------&lt;br&gt;/*&lt;br&gt;**/&lt;br&gt;template&amp;lt; class base, class derive &amp;gt;&lt;br&gt;class AutoRegisterClass&lt;br&gt;{&lt;br&gt;static bool                       m_bRegister;&lt;br&gt;typedef base*                     base_point;   &lt;br&gt;public:&lt;br&gt;    static void RegisterClass( const char* szID )&lt;br&gt;{&lt;br&gt;if( !m_bRegister )&lt;br&gt;{&lt;br&gt;Factory&amp;lt;base&amp;gt;::Instance()-&amp;gt;Register( szID, Create );&lt;br&gt;m_bRegister = true;&lt;br&gt;}&lt;br&gt;}&lt;br&gt;static base_point Create()&lt;br&gt;{&lt;br&gt;return (base_point)(new derive);&lt;br&gt;}&lt;br&gt;};&lt;br&gt;template&amp;lt; class base, class derive &amp;gt;&lt;br&gt;bool AutoRegisterClass&amp;lt;base, derive&amp;gt;::m_bRegister = false;
&lt;p&gt;&lt;br&gt;// 应用测试:&lt;br&gt;class CUICtrl&lt;br&gt;{&lt;br&gt;public:&lt;br&gt;virtual ~CUICtrl() {}&lt;br&gt;};&lt;br&gt;class CUIButton : public CUICtrl&lt;br&gt;{&lt;br&gt;std::string s;&lt;br&gt;public:&lt;br&gt;CUIButton() : s(&amp;quot;CUIButton&amp;quot;) {}&lt;br&gt;void Test()&lt;br&gt;{&lt;br&gt;MessageBox( 0, s.data(), &amp;quot;ok&amp;quot;, 0 );&lt;br&gt;}&lt;br&gt;};&lt;br&gt;class CUIPanel : public CUICtrl&lt;br&gt;{&lt;br&gt;public:&lt;br&gt;void Test()&lt;br&gt;{&lt;br&gt;MessageBox( 0, &amp;quot;CUIPanel&amp;quot;, &amp;quot;ok&amp;quot;, 0 );&lt;br&gt;}&lt;br&gt;};
&lt;p&gt;// using test:&lt;br&gt;void RegisterCtrlClass()&lt;br&gt;{&lt;br&gt;AutoRegisterClass&amp;lt;CUICtrl, CUIButton&amp;gt;::RegisterClass(&amp;quot;CUIButton&amp;quot;);&lt;br&gt;AutoRegisterClass&amp;lt;CUICtrl, CUIPanel&amp;gt;::RegisterClass(&amp;quot;CUIPanel&amp;quot;);&lt;br&gt;}
&lt;p&gt;#define CREATE_OBJ(x)  Factory&amp;lt;CUICtrl&amp;gt;::Instance()-&amp;gt;Create( x );
&lt;p&gt;class CUICtrlMgr&lt;br&gt;{&lt;br&gt;//...&lt;br&gt;};
&lt;p&gt;
&lt;p&gt;int APIENTRY WinMain(HINSTANCE hInstance,&lt;br&gt;                     HINSTANCE hPrevInstance,&lt;br&gt;                     LPSTR     lpCmdLine,&lt;br&gt;                     int       nCmdShow)&lt;br&gt;{&lt;br&gt;RegisterCtrlClass();&lt;br&gt;// CUICtrlMgr.AddCtrl( UICTRL_BTN, &amp;quot;btnTest&amp;quot; );&lt;br&gt;CUICtrl* pTest1 = CREATE_OBJ( &amp;quot;CUIButton&amp;quot; );&lt;br&gt;if( pTest1 )&lt;br&gt;{&lt;br&gt;((CUIButton*)pTest1)-&amp;gt;Test();&lt;br&gt;}&lt;br&gt;// CUICtrlMgr.AddCtrl( UICTRL_PANEL, &amp;quot;pnlTest&amp;quot; );&lt;br&gt;CUICtrl* pTest2 = CREATE_OBJ( &amp;quot;CUIPanel&amp;quot; );&lt;br&gt;if( pTest2 )&lt;br&gt;{&lt;br&gt;((CUIPanel*)pTest2)-&amp;gt;Test();&lt;br&gt;}
&lt;p&gt;// CUICtrlMgr.Release();
&lt;p&gt;return 0;&lt;br&gt;}
&lt;p&gt;//修正一个错误，原来的Delete函数是错误的，已删（这个是临时测试用的代码，请参见马肝的源码）&lt;br&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-8189920746979949719&amp;page=RSS%3a+%e7%b1%bb%e5%b7%a5%e5%8e%82&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=flipcode.spaces.live.com&amp;amp;GT1=flipcode"&gt;</description><comments>http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!122.entry#comment</comments><guid isPermaLink="true">http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!122.entry</guid><pubDate>Fri, 25 Nov 2005 03:19:19 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://flipcode.spaces.live.com/blog/cns!8E578E7901A88369!122/comments/feed.rss</wfw:commentRss><wfw:comment>http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!122.entry#comment</wfw:comment><dcterms:modified>2005-11-27T05:30:24Z</dcterms:modified></item><item><title>仿函数、绑定、桥接、委托相关讨论</title><link>http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!121.entry</link><description>&lt;div&gt;
&lt;p&gt;--------------------------------------------------------------------------------
&lt;p&gt;仿函数、绑定、桥接、委托相关讨论:&lt;br&gt;以下随便讨论下，没突出的中心论点，个中理论只代表我个人观点，难免有错，欢迎指正。&lt;br&gt;一。需求:&lt;br&gt;在事件处理常常会碰到这样的情况：&lt;br&gt;1。接口分离。即invokers(调用者)与(receivers)接收者分离。&lt;br&gt;2。时间分离。
&lt;p&gt;比如说：UI相关元素（按钮、菜单等）就是一个invokers。&lt;br&gt;receivers则是响应命令的对象（如对话框或应用程序本身）。&lt;br&gt;这需要我们要先将UI相关元素的事件响应的接收者在初始化时先保存起来。&lt;br&gt;待后用户按下按钮等再触发（即invokers通过调用对应先前保存的receivers来执行命令）&lt;br&gt;嗯，在delphi、java、vcl、.net中有相关的实现。而vc则需要自己来弄。
&lt;p&gt;&lt;br&gt;二。仿函数的实现:&lt;br&gt;在说仿函数前先说说我们应该怎么保存这些操作相关函数的呢？&lt;br&gt;// 一般的函数我们可以这么存:&lt;br&gt;void (*fun)() = Test;&lt;br&gt;(*fun)();&lt;br&gt;// 而类成员函数可以这么做:&lt;br&gt;void (CTest::*mfn)(); // 或用 typedef void (CTest::*MFN_TEST)(); MFN_TEST mfn;&lt;br&gt;mfn = CTest::Test;&lt;br&gt;CTest a, *p=new CTest;&lt;br&gt;(a.*mfn)(); // 调用方法1&lt;br&gt;(p-&amp;gt;*mfn)(); // 调用方法2&lt;br&gt;如上所述可见为了处理前面所述的事件响应情况，我们通常会用回调函数，&lt;br&gt;就是把类成员函数定义为静态函数，在初始时保存函数地址（与一般函数处理类同）及对应的对象指针，&lt;br&gt;在事件触发时调用对应的静态函数，而该函数中在把指针强制转化为对应类型对象地址，&lt;br&gt;得以操纵该对象的成员变量(嗯，理论上跟成员函数的实现差不多，成员函数会由编译器安插一个&lt;br&gt;this指针作为第1个参数传给函数，以便可以操作该this对象的成员)。
&lt;p&gt;回调函数应用的具体代码如下:&lt;br&gt;1). 回调接口(静态函数法):&lt;br&gt;//======================================================&lt;br&gt;#include &amp;quot;stdafx.h&amp;quot;&lt;br&gt;#include &amp;lt;list&amp;gt;
&lt;p&gt;typedef void(*KEY_RESPOND)(void* /*,param*/);&lt;br&gt;struct CListener&lt;br&gt;{&lt;br&gt;void* pThis;&lt;br&gt;KEY_RESPOND pfn;&lt;br&gt;CListener() : pThis(0), pfn(0){}&lt;br&gt;};&lt;br&gt;class CInput&lt;br&gt;{&lt;br&gt;std::list&amp;lt;CListener*&amp;gt; m_listListener;&lt;br&gt;public:&lt;br&gt;void AddListener( CListener* pListener ){&lt;br&gt;m_listListener.push_back( pListener );&lt;br&gt;}&lt;br&gt;void RemoveListerner( CListener* pListener ){&lt;br&gt;std::list&amp;lt;CListener*&amp;gt;::iterator iter;&lt;br&gt;for( iter = m_listListener.begin(); iter!= m_listListener.end();iter++ ){&lt;br&gt;if( pListener == (*iter) ){&lt;br&gt;m_listListener.erase( iter ); break;&lt;br&gt;}&lt;br&gt;}&lt;br&gt;}&lt;br&gt;void HitOneKey(){&lt;br&gt;std::list&amp;lt;CListener*&amp;gt;::iterator iter;&lt;br&gt;for( iter = m_listListener.begin(); iter!= m_listListener.end();iter++ ){&lt;br&gt;if( (*iter)-&amp;gt;pfn &amp;amp;&amp;amp; (*iter)-&amp;gt;pThis ){&lt;br&gt;(*(*iter)-&amp;gt;pfn)( (*iter)-&amp;gt;pThis );&lt;br&gt;}&lt;br&gt;}&lt;br&gt;}&lt;br&gt;void clearListener(){&lt;br&gt;m_listListener.clear();&lt;br&gt;}&lt;br&gt;};&lt;br&gt;class CUI&lt;br&gt;{&lt;br&gt;public:&lt;br&gt;static void InputProc(void* pThis/*,param*/){&lt;br&gt;__asm int 3 // 下个断点测试下（某些编译器不能这么写，vc可以）&lt;br&gt;}&lt;br&gt;};
&lt;p&gt;CUI ui;&lt;br&gt;CInput input;&lt;br&gt;int _tmain(int argc, _TCHAR* argv[])&lt;br&gt;{&lt;br&gt;// 初始:&lt;br&gt;CListener* pListener = new CListener;&lt;br&gt;pListener-&amp;gt;pfn = &amp;amp;CUI::InputProc;&lt;br&gt;pListener-&amp;gt;pThis = &amp;amp;ui;&lt;br&gt;// 触发:&lt;br&gt;input.AddListener( pListener ); // input即为invokers（调用者，但叫触发者好点）&lt;br&gt;input.HitOneKey(); // 某处事件触发,内部呼叫receivers(这里是原先保存的CUI对象)来真正处理该事件(InputProc(...)方法)。&lt;br&gt;// 清除&lt;br&gt;input.clearListener();&lt;br&gt;if( pListener )&lt;br&gt;{&lt;br&gt;delete pListener;&lt;br&gt;pListener = NULL;&lt;br&gt;}&lt;br&gt;return 0;&lt;br&gt;}&lt;br&gt;//======================================================
&lt;p&gt;// 第2种方法: 回调类(虚函数多态法):&lt;br&gt;//======================================================&lt;br&gt;class IWillBack&lt;br&gt;{&lt;br&gt;public:&lt;br&gt;virtual void InputProc(/*参数略...*/){}&lt;br&gt;};&lt;br&gt;class CInput&lt;br&gt;{&lt;br&gt;public:&lt;br&gt;void RegisterListener(IWillBack* pListener){&lt;br&gt;m_pListener = pListener; // 这里用list存起来才好，这里只作测试&lt;br&gt;}&lt;br&gt;void OnInputEvent(){&lt;br&gt;m_pListener-&amp;gt;InputProc(/*参数略...*/);&lt;br&gt;}
&lt;p&gt;private:&lt;br&gt;IWillBack* m_pListener;&lt;br&gt;};&lt;br&gt;class CUI : public IWillBack&lt;br&gt;{&lt;br&gt;public:&lt;br&gt;void InputProc(/*参数略...*/){ /*..实际处理代码..*/}&lt;br&gt;private:&lt;br&gt;};
&lt;p&gt;int _tmain(int argc, _TCHAR* argv[])&lt;br&gt;{&lt;br&gt;CInput aa;&lt;br&gt;CUI bb;&lt;br&gt;aa.RegisterListener(&amp;amp;bb);&lt;br&gt;aa.OnInputEvent();&lt;br&gt;return 0;&lt;br&gt;}&lt;br&gt;//======================================================
&lt;p&gt;&lt;br&gt;但是第1种静态函数用法是不直观的，第2种需要派生增加了之间的联系，而为了方便我们通常会将成员函数指针转化为函数对象来处理,即仿函数(一般是指重载了()操作符的类)来实现。
&lt;p&gt;类似于这样的操作，stl提供了mem_fun、mem_fun_ref、binder1st、binder2nd简单操作。&lt;br&gt;但stl的方法相对比较原始而受限制，比如说std::mem_fun需要成员函数有返回值,&lt;br&gt;std::mem_fun最多只能支持成员函数有一个参数等，&lt;br&gt;下面来看std:mem_fun_ref不支持成员函数返回值为void的一个例子:&lt;br&gt;//======================================================&lt;br&gt;#include &amp;lt;functional&amp;gt;&lt;br&gt;class CFoo&lt;br&gt;{&lt;br&gt;public:&lt;br&gt;void test() // 只有将void改成别的类型才可以，如:int&lt;br&gt;{&lt;br&gt;return 0;&lt;br&gt;}&lt;br&gt;};&lt;br&gt;void main()&lt;br&gt;{&lt;br&gt;CFoo t;&lt;br&gt;std::mem_fun_ref(&amp;amp;CFoo::test)(t);&lt;br&gt;}&lt;br&gt;//======================================================&lt;br&gt;上述代码只有将void改成别的类型（如int）才可以，&lt;br&gt;那么为什么不可以处理返回void的函数呢? stl的实现究竟是怎么样的呢?&lt;br&gt;嗯，stl简单实现了mem_fun_ref及mem_fun,其中mem_fun_ref以引用方式处理函数所属对象，&lt;br&gt;而mem_fun以指针方式处理函数所属对象。&lt;br&gt;现在让我们从vc的stl挖出部份代码来看看，
&lt;p&gt;1.stl的实现:&lt;br&gt;以mem_fun_ref为例(省略某些对说明不重要的细节，两条虚线包括的代码为stl类似源码):&lt;br&gt;//======================================================&lt;br&gt;//----------------------------------------------------------&lt;br&gt;namespace stl_test&lt;br&gt;{&lt;br&gt;// 主要实现:&lt;br&gt;template&amp;lt;class R, class T&amp;gt;&lt;br&gt;class mem_fun_ref_t&lt;br&gt;{&lt;br&gt;public:&lt;br&gt;mem_fun_ref_t( R (T::*_Pm)() ) : _Ptr(_Pm) {} // 构造: 保存成员函数地址&lt;br&gt;R operator()(T&amp;amp; _X) const // 调用: 这里可看出mem_fun_ref以引用方式处理&lt;br&gt;{&lt;br&gt;return ((_X.*_Ptr)()); // 这里执行调用函数，并返回该函数所返回值&lt;br&gt;}&lt;br&gt;private:&lt;br&gt;R (T::*_Ptr)(); // 指向成员函数地址的指针&lt;br&gt;};&lt;br&gt;// 这里只是利用函数的参数推导来自动获取型别(方便调用)&lt;br&gt;template&amp;lt;class R, class T&amp;gt; inline&lt;br&gt;mem_fun_ref_t&amp;lt;R, T&amp;gt; mem_fun_ref(R (T::*_Pm)())&lt;br&gt;{&lt;br&gt;return (mem_fun_ref_t&amp;lt;R, T&amp;gt;(_Pm));&lt;br&gt;}
&lt;p&gt;} // end of namespace test_stl&lt;br&gt;//----------------------------------------------------------&lt;br&gt;class CFoo&lt;br&gt;{&lt;br&gt;public:&lt;br&gt;int test1(){&lt;br&gt;__asm int 3&lt;br&gt;return 0;&lt;br&gt;}&lt;br&gt;void test2(){&lt;br&gt;__asm int 3&lt;br&gt;}&lt;br&gt;};&lt;br&gt;int APIENTRY WinMain(HINSTANCE hInstance,&lt;br&gt;HINSTANCE hPrevInstance,&lt;br&gt;LPSTR lpCmdLine,&lt;br&gt;int nCmdShow)&lt;br&gt;{&lt;br&gt;CFoo t;&lt;br&gt;stl_test::mem_fun_ref( &amp;amp;CFoo::test1 ) (t);&lt;br&gt;return 0;&lt;br&gt;}&lt;br&gt;//======================================================&lt;br&gt;/////////////////////////////////////////////////////////////////&lt;br&gt;从源码&amp;quot;return ((_X.*_Ptr)()); &amp;quot; 可以看到stl直接返回该函数所返回值。&lt;br&gt;所以函数没有返回值（即为void时）的话编译器就会报错。好，那么如果我们在&lt;br&gt;这里只是直接执行函数而不用return返回的话编译器应该可以通过了。
&lt;p&gt;嗯，boost中正是这么处理的。（btw.为了更为通用，boost对stl原有仿函数及绑定作了大量的改进工作）。&lt;br&gt;但是具体应该怎么区分有没有返回值呢？这个也容易，我们只需用到模板的偏特性就可&lt;br&gt;以做到。下面就看看boost的实现(btw.boost有两种版本，我用的是兼容版本，代码难看)
&lt;p&gt;2. boost的实现(这里我把boost的一大堆宏（真@$@#@#难看，loki在这方面来得比较清爽）去掉了):&lt;br&gt;/////////////////////////////////////////////////////////////////&lt;br&gt;// notreturn.cpp : Defines the entry point for the application.&lt;br&gt;//
&lt;p&gt;#include &amp;quot;stdafx.h&amp;quot;&lt;br&gt;//------------------------------------&lt;br&gt;namespace boost_test&lt;br&gt;{&lt;br&gt;template&amp;lt;class V&amp;gt; // 有返回值时会调用这个&lt;br&gt;struct mf&lt;br&gt;{&lt;br&gt;template&amp;lt;class R, class T&amp;gt;&lt;br&gt;class inner_mf0&lt;br&gt;{&lt;br&gt;R (T::*_Ptr)();&lt;br&gt;public:&lt;br&gt;inner_mf0(R (T::*f)()) : _Ptr(f) {}&lt;br&gt;R operator()(T&amp;amp; X) const&lt;br&gt;{&lt;br&gt;return ((X.*_Ptr)());&lt;br&gt;}&lt;br&gt;};&lt;br&gt;};&lt;br&gt;template&amp;lt;&amp;gt; // 没有反回值时会调用这个&lt;br&gt;struct mf&amp;lt;void&amp;gt; // 偏特化&lt;br&gt;{&lt;br&gt;template&amp;lt;class R, class T&amp;gt;&lt;br&gt;class inner_mf0&lt;br&gt;{&lt;br&gt;R (T::*_Ptr)();&lt;br&gt;public:&lt;br&gt;inner_mf0(R (T::*f)()) : _Ptr(f) {}&lt;br&gt;R operator()(T&amp;amp; X) const&lt;br&gt;{&lt;br&gt;((X.*_Ptr)());&lt;br&gt;}&lt;br&gt;};&lt;br&gt;};&lt;br&gt;// 创建一派生类,派生于上述基类&lt;br&gt;template&amp;lt;class R, class T&amp;gt;&lt;br&gt;struct mf0 : public mf&amp;lt;R&amp;gt;::inner_mf0&amp;lt;R, T&amp;gt;&lt;br&gt;{&lt;br&gt;typedef R(T::*F)();&lt;br&gt;explicit mf0(F f) : mf&amp;lt;R&amp;gt;::inner_mf0&amp;lt;R, T&amp;gt;(f) {}&lt;br&gt;};&lt;br&gt;// 通过函数的参数推导自动获取类型&lt;br&gt;template&amp;lt;class R, class T&amp;gt;&lt;br&gt;mf0&amp;lt;R, T&amp;gt; mem_fn( R(T::*f)() )&lt;br&gt;{&lt;br&gt;return mf0&amp;lt;R, T&amp;gt;(f);&lt;br&gt;}&lt;br&gt;} // namespace boost_test&lt;br&gt;//------------------------------------
&lt;p&gt;class CFoo&lt;br&gt;{&lt;br&gt;public:&lt;br&gt;int test1(){ return 0; }&lt;br&gt;void test2(){}&lt;br&gt;};&lt;br&gt;int APIENTRY WinMain(HINSTANCE hInstance,&lt;br&gt;HINSTANCE hPrevInstance,&lt;br&gt;LPSTR lpCmdLine,&lt;br&gt;int nCmdShow)&lt;br&gt;{&lt;br&gt;CFoo t;&lt;br&gt;boost_test::mem_fn( &amp;amp;CFoo::test1 ) (t);&lt;br&gt;return 0;&lt;br&gt;}&lt;br&gt;/////////////////////////////////////////////////////////////////
&lt;p&gt;从上述代码可以看到偏特性帮助我们解决了返回值为void的情况。但是手写了两份&lt;br&gt;基本相同的代码。。。&lt;br&gt;另外处理参数个数的情况也很容易，只要分别实现不同参数的各个模板类就可以了，&lt;br&gt;boost最多只能支持成员函数有8个参数，因为它内部实现了8份这样不同参数模板类。&lt;br&gt;其实的处理方法都是一模一样的，可是由于语言的限制我们还是没有办法不一一实现&lt;br&gt;不同参数的类:。在loki中参数可以用TList实现任意的参数，但是在实现还是得老&lt;br&gt;老实实的每份手写一份（loki实现了15份可以支持15个参数）。&lt;br&gt;这真让人郁闷。。。不过没办法。
&lt;p&gt;说完来仿函数，下面开始说说有关绑定，stl、boost、loki的绑定的意思是&lt;br&gt;对某物实体的“绑定”，通俗来说是指对函数、构造函数、仿函数等与其对应的某个参数的绑定，&lt;br&gt;以便在调用时不用再次输入此参数（因为某些时候参数是固定的，比如说绑定一个内部存有&lt;br&gt;成员函数地址的仿函数和它对应的对象地址在一起）。&lt;br&gt;以下是stl的bind用法:&lt;br&gt;//================================&lt;br&gt;#include &amp;quot;stdafx.h&amp;quot;&lt;br&gt;#include &amp;lt;functional&amp;gt; // stl&lt;br&gt;#include &amp;lt;function.hpp&amp;gt; // boost
&lt;p&gt;struct CFoo {&lt;br&gt;int test(int){&lt;br&gt;return 0;&lt;br&gt;}&lt;br&gt;};&lt;br&gt;void main()&lt;br&gt;{&lt;br&gt;boost::function1&amp;lt;int, int&amp;gt; f; // 这里用了boost&lt;br&gt;CFoo obj;&lt;br&gt;f = std::bind1st(std::mem_fun(&amp;amp;CFoo::test), &amp;amp;obj);&lt;br&gt;f(5);&lt;br&gt;}&lt;br&gt;//================================&lt;br&gt;loki中的BindFirst比较类似于stl的binder&lt;br&gt;(binder1st，binder2nd)，但是它是通用的，可以通过嵌套实现任意多个参数绑定：&lt;br&gt;//================================&lt;br&gt;void f()&lt;br&gt;{&lt;br&gt;Functor&amp;lt;void, TYPELIST_2(int, int)&amp;gt; cmd1(something);&lt;br&gt;Functor&amp;lt;void, TYPELIST_1(int)&amp;gt; cmd2(BindFirst(cmd1, 10));&lt;br&gt;cmd2(20);&lt;br&gt;Functor&amp;lt;void&amp;gt; cmd3(BindFirst(cmd2, 30));&lt;br&gt;cmd3();&lt;br&gt;}
&lt;p&gt;而boost中的实现是以占位符来表现,具体如何实现，下回继续讨论(嗯，&lt;br&gt;boost代码的宏太多了，这部份还是等有空再补全了，现在我们来看看如何实现一个委托类)
&lt;p&gt;三。委托类的实现:&lt;br&gt;1. 桥接模式:&lt;br&gt;设计模式告诉我们可以使用桥接模式(Bridge Pattern)减少对象之间的 耦合度，桥接模式如下:&lt;br&gt;Invoker &amp;lt;&amp;gt;-------------------&amp;gt;* Interface&lt;br&gt;^&lt;br&gt;|&lt;br&gt;Receiver&lt;br&gt;上图的Invoker表示事件触发者，Receiver表示事件处理者，符号类似于＜c++大规模编程。。＞一书所描述，&lt;br&gt;其中&amp;lt;&amp;gt;-------------------&amp;gt;表示Invoker 内含(拥用)Interface(即Invoker 有Interface的变量或指针并负责Interface的释放)，&lt;br&gt;而*号表示可有多个。&lt;br&gt;^&lt;br&gt;| 　号则表示继承于（Receiver继承于Interface）。
&lt;p&gt;好，我们先来分析前面在&amp;quot; 第2种方法: 回调类(虚函数多态法):&amp;quot;的实现思想(请回到前面看看代码)，&lt;br&gt;它其实就是一个桥接模式，如下(括号内对应前面所实现的类)：&lt;br&gt;Invoker(CInput) &amp;lt;&amp;gt;---------------&amp;gt;* Interface（IWillBack）&lt;br&gt;^&lt;br&gt;|&lt;br&gt;Receiver（CUI）&lt;br&gt;对照我们前面实现的代码可以发现此种实现的桥接的缺点是：每一个想要&lt;br&gt;注册一方法到Invoker中以便Invoker在事件触发时调用的类(如Receiver)都要派生自Interface。&lt;br&gt;有没有更好的办法再次减少这种耦合度呢？这正是下面我们要讨&lt;br&gt;论的下一种设计模式：&lt;br&gt;2. 委托与事件:&lt;br&gt;委托的处理设计如下:&lt;br&gt;Invoker &amp;lt;&amp;gt;---------------------&amp;gt;* Interface&lt;br&gt;^&lt;br&gt;|&lt;br&gt;Implementation -----------------&amp;gt; Receiver&lt;br&gt;即在原桥接模式下再加一层间接性:Implementation 。其中&lt;br&gt;Implementation与Receiver之间的-----------------&amp;gt;表示Implementation引用了Receiver一些服务，&lt;br&gt;即Implementation用到了Receiver某些东西（如函数或数据）。嗯，这些解释不知是否适当，希望不会误导。。。&lt;br&gt;好，一开始可能我们会这么设计:&lt;br&gt;//======================================================================================&lt;br&gt;class handle {};&lt;br&gt;template &amp;lt;class T&amp;gt;&lt;br&gt;class Implementation : public handle&lt;br&gt;{&lt;br&gt;T* m_pThis;&lt;br&gt;public:&lt;br&gt;Implementation ( T* pThis ) : m_pThis(pThis) {}&lt;br&gt;template&amp;lt;class T1&amp;gt;&lt;br&gt;void execute( void (T::*mfn)(T1), T1 arg ) { (m_pThis-&amp;gt;*mfn)( arg ); }
&lt;p&gt;};&lt;br&gt;struct Receive {&lt;br&gt;void Proc(int) {&lt;br&gt;__asm int 3&lt;br&gt;}&lt;br&gt;};&lt;br&gt;Receive a;&lt;br&gt;void Invoker(){&lt;br&gt;Implementation&amp;lt;Receive&amp;gt; test = Implementation &amp;lt;Receive&amp;gt;(&amp;amp;a);&lt;br&gt;test.execute( Receive::Proc, 10 ); // 当事件发生时调用&lt;br&gt;};&lt;br&gt;int _tmain(int argc, _TCHAR* argv[])&lt;br&gt;{&lt;br&gt;Invoker();&lt;br&gt;}&lt;br&gt;//======================================================================================&lt;br&gt;但是Invoker知道了太多Receive的信息，况且我们想让触发者Invoker作成一个类。&lt;br&gt;一个改进的版本如下:&lt;br&gt;//-------------------------------------------------------------&lt;br&gt;// signal slot system&lt;br&gt;// 注: 该法我是看了&amp;quot;落木随风&amp;quot;的&amp;quot;委托、信号和消息反馈的模板实现技术&amp;quot;，&lt;br&gt;// 代码作了部份添加。在这里非常的感谢他!&lt;br&gt;// 他的博客：&lt;a href="http://blogs.gcomputing.com/rocwood...ves/000154.html" target="_blank"&gt;&lt;u&gt;&lt;font color="#0000ff"&gt;http://blogs.gcomputing.com/rocwood...ves/000154.html&lt;/font&gt;&lt;/u&gt;&lt;/a&gt;&lt;br&gt;//-------------------------------------------------------------&lt;br&gt;// Delegation.cpp : Defines the entry point for the console application.&lt;br&gt;//&lt;br&gt;#include &amp;lt;windows.h&amp;gt;
&lt;p&gt;#ifndef K_DELEGATE_H&lt;br&gt;#define K_DELEGATE_H
&lt;p&gt;namespace kUTIL&lt;br&gt;{&lt;br&gt;// 1. 桥接类(纯虚类):&lt;br&gt;// 为什么叫作桥接?&lt;br&gt;// 因为通过它的虚函数方法可以调用到对应的正确的不同派生实例(指后面&lt;br&gt;// 提到的委托人)所改写的虚函数方法(这是委托人用来完成委托任务的方法)&lt;br&gt;struct kDelegationInterface&lt;br&gt;{&lt;br&gt;virtual ~kDelegationInterface() {};&lt;br&gt;virtual void Execute() = 0;&lt;br&gt;};&lt;br&gt;// 2. 委托类(派生于桥接类，这里我叫为”委托人“)&lt;br&gt;// 为什么叫委托？&lt;br&gt;// 因为调用者把“通知”的工作委托给它来负责处理。&lt;br&gt;// 一个“委托人”保存了: a.”接收者“(对象指针m_pThis) 及 b.“要作的事”(方法指针m_mfn)，&lt;br&gt;// 以便调用者发出信号弹(后面提到,信号弹有一个作桥接用的纯虚类的指针指向相应的委托人)&lt;br&gt;// 告知此信号对应的委托人来完成它被委托的工作：即让“接收者”(m_pThis)作”要作的事“(m_mfn)。&lt;br&gt;template&amp;lt;class T&amp;gt;&lt;br&gt;struct kDelegationImpl : public kDelegationInterface&lt;br&gt;{&lt;br&gt;typedef void ( T::* MFN )();&lt;br&gt;kDelegationImpl( T* pthis, MFN mfn ) : m_pThis( pthis ), m_mfn( mfn ) {&lt;br&gt;}&lt;br&gt;virtual void Execute() {&lt;br&gt;if( m_pThis ) { &lt;br&gt;( m_pThis-&amp;gt;*m_mfn )(); &lt;br&gt;}&lt;br&gt;}&lt;br&gt;T*  m_pThis;&lt;br&gt;MFN m_mfn;&lt;br&gt;};
&lt;p&gt;// 3. 信号弹(实现为仿函数来调用统一的虚函数接口):&lt;br&gt;// 为什么叫信号？&lt;br&gt;// 因为当&amp;quot;信号弹&amp;quot;发射时(调用信号的操作符&amp;quot;()&amp;quot;)&lt;br&gt;// 它会通知所指向的&amp;quot;委托人&amp;quot;事件发生了(调用纯虚类指针的m_DI-&amp;gt;Execute()方法)。&lt;br&gt;// 一个信号保存了一个指向对应”委托人“的桥接类(纯虚类)指针。&lt;br&gt;struct kSignal0&lt;br&gt;{&lt;br&gt;kDelegationInterface* m_DI; // 纯虚类的指针&lt;br&gt;kSignal0() : m_DI(0) {}&lt;br&gt;// 1. 纯虚类的m_DI指针可以指向不同的派生实例:&lt;br&gt;template&amp;lt;class T&amp;gt;&lt;br&gt;void ConnectSlot(T* recv, void (T::* mfn)()) {&lt;br&gt;DisConnect();&lt;br&gt;m_DI = new kDelegationImpl&amp;lt;T&amp;gt;( recv, mfn );&lt;br&gt;int test = 0;&lt;br&gt;}&lt;br&gt;void DisConnect() {&lt;br&gt;if( m_DI ) { delete m_DI; m_DI = NULL; }&lt;br&gt;}&lt;br&gt;// 2. 用统一的纯虚类指针调用不同派生类改写的虚函数&lt;br&gt;void operator() () { &lt;br&gt;if( m_DI ) {&lt;br&gt;m_DI-&amp;gt;Execute(); &lt;br&gt;}&lt;br&gt;}&lt;br&gt;};
&lt;p&gt;// 下面是两个为方便使用的函数:&lt;br&gt;template&amp;lt;class T&amp;gt;&lt;br&gt;void kConnect( kSignal0&amp;amp; sgn, T* pObj, void(T::*fn)())&lt;br&gt;{&lt;br&gt;sgn.ConnectSlot( pObj, fn );&lt;br&gt;int i  = 0;&lt;br&gt;}&lt;br&gt;inline void kDisConnect( kSignal0&amp;amp; sgn )&lt;br&gt;{&lt;br&gt;sgn.DisConnect();&lt;br&gt;}&lt;br&gt;} // end of namespace kUTIL&lt;br&gt;#endif //#ifndef K_DELEGATE_H
&lt;p&gt;&lt;br&gt;//----------------------------------------------------------------------------&lt;br&gt;// 一个使用实例:&lt;br&gt;class kButton {&lt;br&gt;public:&lt;br&gt;kUTIL::kSignal0 sgnMouseBtnUp;&lt;br&gt;void onMouseButtonUp() { sgnMouseBtnUp(); }&lt;br&gt;};
&lt;p&gt;class kDialog {&lt;br&gt;kButton btn;&lt;br&gt;public:&lt;br&gt;kDialog() {&lt;br&gt;kUTIL::kConnect( btn.sgnMouseBtnUp, this, &amp;amp;kDialog::DoWork ); // vc6下这里kDialog::DoWork的前面一定要可加&amp;quot;&amp;amp;&amp;quot;号&lt;br&gt;}&lt;br&gt;void DoWork() { &lt;br&gt;__asm int 3&lt;br&gt;}&lt;br&gt;void TestMouseHit() { btn.onMouseButtonUp(); }&lt;br&gt;};
&lt;p&gt;&lt;br&gt;int main(int argc, char* argv[])&lt;br&gt;{&lt;br&gt;kDialog dlg;&lt;br&gt;kButton btn;&lt;br&gt;kUTIL::kConnect( btn.sgnMouseBtnUp, &amp;amp;dlg, kDialog::DoWork ); // vc6下这里kDialog::DoWork的前面可加/不加&amp;quot;&amp;amp;&amp;quot;号
&lt;p&gt;// 测试一:&lt;br&gt;btn.onMouseButtonUp();
&lt;p&gt;// 测试二:&lt;br&gt;dlg.TestMouseHit();&lt;br&gt;return 0;&lt;br&gt;}
&lt;p&gt;// 委托实例总结：&lt;br&gt;// 下面我们来具体说明”当某事发生时，调用者发射信号弹通知对应的接收者作相应处理“&lt;br&gt;// 1. &amp;quot;调用者&amp;quot; 拥有各种信号弹。&lt;br&gt;// 2. 初始时，我们把信号弹与对应的委托人联系起来，并让委托人记录在信号触发时应该通知的&amp;quot;接收人&amp;quot;和&amp;quot;接收人该作的事&amp;quot;。&lt;br&gt;//    a. 信号弹保存了桥(纯虚类)指针，指针指向通过其模板函数ConnectSlot方法来找出(产生的)委托人(委托实例)。&lt;br&gt;//    b. 委托人(委托实例)在信号弹用ConnectSlot方法产生它的时候保存了函数ConnectSlot所传入的两个参数：&lt;br&gt;//    即&amp;quot;接收者指针&amp;quot;及&amp;quot;其方法指针&amp;quot;。&lt;br&gt;// 3. 当事件发生时&amp;quot;调用者&amp;quot;发射对应信号弹后，信号弹会调用其所保存的纯虚类指针的虚函数方法，&lt;br&gt;//    于是由于虚函数特性就会调用到其所指向的委托实例(委托人)所改写的方法。&lt;br&gt;// 5. 委托人改写的方法中通过其所保存的”接收者指针“及其&amp;quot;方法指针&amp;quot;来呼叫&amp;quot;接收者&amp;quot;用对应的”方法指针“&lt;br&gt;//    来处理事情。&lt;br&gt;// 即如下流程:&lt;br&gt;// &amp;quot;调用者&amp;quot;发射&amp;quot;信号弹&amp;quot; ---&amp;gt; &amp;quot;信号弹&amp;quot;通过&amp;quot;桥&amp;quot;找到对应&amp;quot;委托人&amp;quot; ---&amp;gt; &amp;quot;委托人&amp;quot;呼叫&amp;quot;接收者&amp;quot;作&amp;quot;该作的事&amp;quot;
&lt;p&gt;//=============================================================================&lt;br&gt;嗯，这样到此，一个非常方便的委托类就得以实现了！如果你还不懂的话请仔细的琢磨，如此精华(因为简单而强大)&lt;br&gt;不要错过。不过上述只是部份实现，当你要支持带参数及返回值的各种情况的话，还得自己作扩充。&lt;br&gt;返回值的处理方法可参见前面剖述boost的mem_fn的处理方法，而带不同参数的处理则只能一一手动&lt;br&gt;实现，就象前面所说的那样，这是很无奈的事情，但是目前来说没有办法。。。
&lt;p&gt;(待续。。。。。。,如果有时间有必要的话。。。)
&lt;p&gt;&lt;br&gt;附:&lt;br&gt;loki下载:&lt;br&gt;http://sourceforge.net/projects/loki-lib/
&lt;p&gt;boost下载:&lt;br&gt;http://sourceforge.net/projects/boost/
&lt;p&gt;&lt;br&gt;2004.10.26更新：&lt;br&gt;修正:&lt;br&gt;原void connect( Signal0&amp;amp; sgn,T1 obj, void(T2::*fn)())改成&lt;br&gt;void connect( Signal0&amp;amp; sgn,T1&amp;amp; obj, void(T2::*fn)())&lt;br&gt;另外加了kDisConnect释放内存，原来只作测试没写它，现在还是加上了。
&lt;p&gt;
&lt;p&gt;&lt;br&gt;
&lt;div align=right&gt;&lt;img src="http://bbs.gameres.com/style/snow/image/ok.gif" border=0&gt;flipcode 2005-1-6 17:54:48&lt;/div&gt;&lt;br&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-8189920746979949719&amp;page=RSS%3a+%e4%bb%bf%e5%87%bd%e6%95%b0%e3%80%81%e7%bb%91%e5%ae%9a%e3%80%81%e6%a1%a5%e6%8e%a5%e3%80%81%e5%a7%94%e6%89%98%e7%9b%b8%e5%85%b3%e8%ae%a8%e8%ae%ba&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=flipcode.spaces.live.com&amp;amp;GT1=flipcode"&gt;</description><comments>http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!121.entry#comment</comments><guid isPermaLink="true">http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!121.entry</guid><pubDate>Fri, 25 Nov 2005 03:18:08 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://flipcode.spaces.live.com/blog/cns!8E578E7901A88369!121/comments/feed.rss</wfw:commentRss><wfw:comment>http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!121.entry#comment</wfw:comment><dcterms:modified>2005-11-27T05:30:45Z</dcterms:modified></item></channel></rss>