如:
在VB工程工添加一个类  calss2
Public Event a()
Public Sub b()
    RaiseEvent a
End Sub在form1中:
Public WithEvents s As Class2Private Sub Command1_Click()
    Set s = New Class2
    s.b
End SubPrivate Sub s_a()
    MsgBox "this is event"
End Sub这样的功能,在VC中怎么做???大虾们,请给示例代码,好吗?别讲道理,欧笨!!!活活,谢谢!

解决方案 »

  1.   

    三种方法:
    1、在类管理器中你想要添加消息的右键菜单中,有几个命令:添加成员变量、添加成员函数、添加虚函数、添加消息响应函数,你可以进行相应的操作,如选择“添加消息响应函数”,里面会列出很多消息响应,在左边选中,双击,然后选择右边的“编辑”命令,就可以添加一个消息响应了,里面可以添加你想要的语句;2、直接在ClassWizard里面操作,按Ctrl+W,打开类向导,里面有几个标签,可以添加消息响应函数和变量,选中对应的类和对应的控件(或菜单)的ID,具体和上面的方法类似;3、如果给控件添加消息响应函数,在界面编辑里,右键单击控件,选择弹出菜单中底部的“事件(Event)”,就会弹出该控件所有消息响应命令,添加方法和上面的类似。
      

  2.   

    VC中想要做到楼主的功能,一般来说不是用事件的,而是给他们发送一个信号(消息)在VC中,一般都是用消息传递的。
      

  3.   

    呵呵, 楼主对Windows的消息机制还不是特别清楚啊,一楼已经给出了方法,你应该看看Windows程序设计之类的书
      

  4.   

    好了,大家不要框框而谈了,上边的方法其实是一种!使用消息循环,
    首先,谢谢 fengqinggao(风清高) ,但是不是俺想要的!!!
    但是仔细看,如果在控件或者COM组件中,是在消息循环下又封装了一层,
    谁知道封装的这一层的机制(就是连接点机制)???
    并且,我知道,上边的VB程序,
    其机制肯定不是消息循环并且也不完全是连接点!!!
    又水知道,不胜感激???分不够再加!!!大虾们肯定做过ATL中的COM事件,以及net中的事件把?
    COM是使用的连接点!!!
    net中的事件我知道肯定是回调函数,但是我不知道具体的机制,希望能给代码演示一下!
    希望给代码!!!就象 class a{}
         calss b{}
        在a中声明b,然后在a中的一个事件函数,可以响应b发出的事件!!!
      

  5.   

    fengqinggao(风清高) 大虾,你没有错,俺真的是新手,呵呵!你的星,佩服得欧好眼红啊,呵呵!!!
    不过,这个问题已经郁闷了我好久了,也找了好多资料,但是都是只是给一些概念上的东东,没有具体的代码!!!迫不得以,麻烦虾们了,呵呵,还请多多帮忙,活活!其实,这篇文章写的很清楚了,不过就是没有示例代码!!!活活。
    我贴出来,请大家一定要帮欧。。谢谢 ^.^特别是这段"此种回调方式比传统回调函数要高明许多...."  >>>> 是怎么实现的????机制是什么???/***********************************************
       回调函数、消息和事件例程
        调用(calling)机制从汇编时代起已经大量使用:准备一段现成的代码,调用者可以随时跳转至此段代码的起始地址,执行完后再返回跳转时的后续地址。CPU为此准备了现成的调用指令,调用时可以压栈保护现场,调用结束后从堆栈中弹出现场地址,以便自动返回。借堆栈保护现场真是一项绝妙的发明,它使调用者和被调者可以互不相识,于是才有了后来的函数和构件,使吾辈编程者如此轻松愉快。若评选对人类影响最大之发明,在火与车轮之后,笔者当推压栈调用。
        话虽这样说,此调用机制并非完美。回调函数就是一例。函数之类本是为调用者准备的美餐,其烹制者应对食客了如指掌,但实情并非如此。例如,写一个快速排序函数供他人调用,其中必包含比较大小。麻烦来了:此时并不知要比较的是何类数据--整数、浮点数、字符串?于是只好为每类数据制作一个不同的排序函数。更通行的办法是在函数参数中列一个回调函数地址,并通知调用者:君需自己准备一个比较函数,其中包含两个指针类参数,函数要比较此二指针所指数据之大小,并由函数返回值说明比较结果。排序函数借此调用者提供的函数来比较大小,借指针传递参数,可以全然不管所比较的数据类型。被调用者回头调用调用者的函数(够咬嘴的),故称其为回调(callback)。
        回调函数使程序结构乱了许多。Windows API 函数集中有不少回调函数,尽管有详尽说明,仍使初学者一头雾水。恐怕这也是无奈之举。无论何种事物,能以树形结构单向描述毕竟让人舒服些。如果某家族中孙辈又是某祖辈的祖辈,恐怕无人能理清其中的头绪。但数据处理之复杂往往需要构成网状结构,非简单的客户/服务器关系能穷尽。
        Windows 系统还包含着另一种更为广泛的回调机制,即消息机制。消息本是 Windows 的基本控制手段,乍看与函数调用无关,其实是一种变相的函数调用。发送消息的目的是通知收方运行一段预先准备好的代码,相当于调用一个函数。消息所附带的 WParam 和 LParam 相当于函数的参数,只不过比普通参数更通用一些。应用程序可以主动发送消息,更多情况下是坐等 Windows 发送消息。一旦消息进入所属消息队列,便检感兴趣的那些,跳转去执行相应的消息处理代码。操作系统本是为应用程序服务,由应用程序来调用。而应用程序一旦启动,却要反过来等待操作系统的调用。这分明也是一种回调,或者说是一种广义回调。其实,应用程序之间也可以形成这种回调。假如进程 B 收到进程 A 发来的消息,启动了一段代码,其中又向进程 A 发送消息,这就形成了回调。这种回调比较隐蔽,弄不好会搞成递归调用,若缺少终止条件,将会循环不已,直至把程序搞垮。若是故意编写成此递归调用,并设好终止条件,倒是很有意思。但这种程序结构太隐蔽,除非十分必要,还是不用为好。
        利用消息也可以构成狭义回调。上面所举排序函数一例,可以把回调函数地址换成窗口 handle。如此,当需要比较数据大小时,不是去调用回调函数,而是借 API 函数 SendMessage 向指定窗口发送消息。收到消息方负责比较数据大小,把比较结果通过消息本身的返回值传给消息发送方。所实现的功能与回调函数并无不同。当然,此例中改为消息纯属画蛇添脚,反倒把程序搞得很慢。但其他情况下并非总是如此,特别是需要异步调用时,发送消息是一种不错的选择。假如回调函数中包含文件处理之类的低速处理,调用方等不得,需要把同步调用改为异步调用,去启动一个单独的线程,然后马上执行后续代码,其余的事让线程慢慢去做。一个替代办法是借 API 函数 PostMessage 发送一个异步消息,然后立即执行后续代码。这要比自己搞个线程省事许多,而且更安全。
        如今我们是活在一个 object 时代。只要与编程有关,无论何事都离不开 object。但 object 并未消除回调,反而把它发扬光大,弄得到处都是,只不过大都以事件(event)的身份出现,镶嵌在某个结构之中,显得更正统,更容易被人接受。应用程序要使用某个构件,总要先弄清构件的属性、方法和事件,然后给构件属性赋值,在适当的时候调用适当的构件方法,还要给事件编写处理例程,以备构件代码来调用。何谓事件?它不过是一个指向事件例程的地址,与回调函数地址没什么区别。
        不过,此种回调方式比传统回调函数要高明许多。首先,它把让人不太舒服的回调函数变成一种自然而然的处理例程,使编程者顿觉气顺。再者,地址是一个危险的东西,用好了可使程序加速,用不好处处是陷阱,程序随时都会崩溃。现代编程方式总是想法把地址隐藏起来(隐藏比较彻底的如 VB 和 Java),其代价是降低了程序效率。事件例程使编程者无需直接操作地址,但并不会使程序减速。更妙的是,此一改变,本是有损程序结构之奇技怪巧变成一种崭新设计理念,不仅免去被人抨击,而且逼得吾等凡人净手更衣,细细研读,仰慕至今。只是偶然静心思虑,发觉不过一瓶旧酒而已,故引得此番议论,让诸君见笑了。作者Blog:http://blog.csdn.net/xiaoran///**********************************************/
      

  6.   

    感觉全文只说了一个意思:消息也是回调函数的一种,是更广义的回调函数(因为操作系统本是为应用程序服务,由应用程序来调用;而应用程序一旦启动,却要反过来等待操作系统的调用)它之所以高明,在于它符合用户的习惯,以按钮为例,单击按钮,就给程序(或者系统)发一个“某按钮被单击”的消息,该消息会触发一个函数,如“背景颜色”按钮ID为IDC_BACK_COLOR,其按钮单击按钮消息触发OnBackColor()函数,该函数定义如下:
    1、在头文件中:
    afx_msg void OnBackColor();
    2、在执行文件中,将上面定义的函数映射给相应ID:
    ON_BN_CLICKED(IDC_BACK_COLOR, OnBackColor)
    3、在执行文件中,有函数:
    void CYourDlg::OnBackColor() 
    {
    AfxMessageBox("您点击了 设置背景颜色 按钮");
    }这就是消息响应过程,至于是不是机制,不清楚,这个响应消息的函数的添加方法就是按一开始说的方法添加的,和VB一样,双击一个按钮也就得到这个消息(默认的)。这里也可以对其他类进行操作,具体就不写了,晚上有很多现成的代码感觉还没有深入,只怕还不是你想要的,呵呵
      

  7.   

    哈哈,终于有了!!!多谢fengqinggao(风清高) 使用回调函数的例子:
    #include "stdafx.h"
    #include <iostream>
    using namespace std;//事件函数的指针
    typedef void (*EventHandler)(char *);//发出事件类
    class A
    {
    //声明事件函数指针
    private:
    EventHandler pEvent;
    public:
    A()
    {
    pEvent =NULL;
    };
    ~A(){};
    //包装事件
    private:
    void Fire_A_Event(char* sMsg)
    {
    if (pEvent != NULL)
    {
    (*pEvent)(sMsg);
    }
    return;
    }//产生事件的方法
    public:
    void AA()
    {
    cout << "A::AA start" << endl;
    Fire_A_Event("Fire A:A_EVENT");
    cout << "A::AA End" << endl;
    };
    //连接点
    public:
     void ConnectPoint(EventHandler pE)
    {
    pEvent = pE;
    };
    };//接收事件类
    class B
    {//建立事件连接点,并调用事件类的方法产生事件
    public:
    void BB()
    {
    A a;
    a.ConnectPoint(A_Event);
    a.AA();
    };//实现事件
    public:
    static void A_Event(char* sMsg)
    {
    cout << "B::A_Event start" << endl;
    cout << sMsg << endl;
    cout << "B Resive A::A_Event" << endl;
    cout << "B::A_Event end" << endl;
    return;
    };
    };int main(int argc, char* argv[])
    {
    B b;
    b.BB();
    return 0;
    }使用interface接口的例子:
    #include "stdafx.h"
    #include <iostream>
    #include <objbase.h>   // Define interface.
    using namespace std;//声明事件类型
    typedef void(*pFUNEVENT)();interface IEvent
    {
    public:
    virtual void A_Event(char*) = 0;
    };//发出事件类
    class A
    {
    //声明事件函数指针
    private:
    IEvent *pEvent;
    public:
    A()
    {
    pEvent =NULL;
    };
    ~A(){};
    //包装事件
    private:
    void Fire_A_Event(char* sMsg)
    {
    if (pEvent != NULL)
    {
    pEvent->A_Event(sMsg);
    }
    return;
    }//产生事件的方法
    public:
    void AA()
    {
    cout << "A::AA start" << endl;
    Fire_A_Event("Fire A:A_EVENT");
    cout << "A::AA End" << endl;
    };
    //连接点
    public:
    void ConnectPoint(IEvent *pE)
    {
    pEvent = pE;
    };
    };//接收事件类
    class B:public IEvent
    {//建立事件连接点,并调用事件类的方法产生事件
    public:
    void BB()
    {
    A a;
    a.ConnectPoint(this);
    a.AA();
    };//实现事件
    public:
    virtual void A_Event(char* sMsg)
    {
    cout << "B::A_Event start" << endl;
    cout << sMsg << endl;
    cout << "B Resive A::A_Event" << endl;
    cout << "B::A_Event end" << endl;
    return;
    };
    };int main(int argc, char* argv[])
    {
    B b;
    b.BB();
    return 0;
    }
      

  8.   

    这些天利用空余时间,俺找了好多资料,还是一头雾水,昨天晚上终于有了点突破,现在把过程卸下来,请虾们指正,呵呵,刚刚学习VC不久,有一些概念不是太精确,还请原谅!!!
    问题的引出:俺在做一个项目时,在CFrameWnd类中,声明了一个继承自CWnd类的自定义类CConCnd,在CConWnd类中,又声明了一个CTreeView控件。实际操作中,需要把CTreeView控件的节点点击事件引出到CFrameWnd中,因为考虑到CConWnd类是一个通用类,所以不想与CFrameWnd产生紧耦合,因为看到VB中的办法,开始就是想用上边的方法,后来时间问题,还是使用了MFC的消息机制,在WINPROC中截获控件消息,然后再发到CFrameWnd中去。不过,当时认为这个不是更好的办法!!!于是,开了笨贴自,并问了朋友们中得几个高手,都没有给很好的解决。于是,俺就开始思考了首先,参考了VB与net,但是由于VB封装的太严密,net讲的又太深奥,所以又回到了VC中。
    然后,想到了以前写的串口的小程序,用到了MSCOMM控件,其中就有事件,看到了这一行ON_EVENT(CCommSRDlg, IDC_MSCOMM1, 1 /* OnComm */, OnComm, VTS_NONE),特别是IDC_MSCOMM1,从中间得到了启发。MFC在事件消息后便肯定又做了一些事情
    然后,想到了COM组件,也可以发出事件,但是没有这个控件ID号,那么在MFC中是怎样响应她的事件的呢???
    于是,欧用ATL做了一个小COM(VCComEvent.dll),只有一个方法A与一个事件C,同时在A中发出事件C,如代码:
    STDMETHODIMP CA::A()
    {
    // TODO: Add your implementation code here
    MessageBox(NULL,"A","COM Event",MB_OK + MB_ICONINFORMATION);
    Fire_C();
    return S_OK;
    }
    然后,欧有打开VC,import组件"VCComEvent.dll"后,却不知道怎样使用这个事件,于是遍查以前看过的资料(inside com/COM&DCOM_Programming/COM与COM+从入门到精通/VC6技术内幕/VC6高级编程等等),发现有一个连接点与事件源的问题,好像要把类与事件源绑定才行(就是把声明事件的类的指针传给组件知道),看到一个函数“FindConnectionPoint”就是干这件事情的,于是再遍查MSDN,结果,终于找到一篇:HOWTO: Catch Microsoft Excel Application Events Using VC++,说的极其详细,哈哈,照着上边一做,果然成功。
    部分代码如下:
    #import "../VCComEvent\Debug\VCComEvent.dll"
    static const GUID  DIID__IAEvents = {0xFFCB22E7,0x8FDA,0x49EC,{0x89,0xBB,0x13,0xD5,0x78,0x89,0x58,0x55}};
    /////////////////////////////void CVCEventClientDlg::OnButton1() 
    {
    // TODO: Add your control notification handler code here
    CoInitialize(NULL);
    IConnectionPointContainer   *pCPC = NULL; VCCOMEVENTLib::IAPtr A;

    A.CreateInstance("VCCOMEVENT.A");
    //pCComEventLgx = new l();

    LPUNKNOWN pUnk = pCComEventLgx.GetInterface(&IID_IUnknown);
    A.QueryInterface(IID_IConnectionPointContainer, &pCPC); pCPC->FindConnectionPoint(DIID__IAEvents, &pCP);
    pCPC->Release();   // Always Release now, even before checking.
    pCP->Advise(pUnk, &dwEvtClass);   //Turn on event support.
    pCP->Release(); A->A();

    A.Release();
    CoUninitialize();
    }
    其中类L为MFC中得一个支持AUTOMATION的类,事件响应函数就在里边做,如下:
    #if !defined(AFX_L_H__D501315F_7DEA_4BDA_973E_9B286E6DC936__INCLUDED_)
    #define AFX_L_H__D501315F_7DEA_4BDA_973E_9B286E6DC936__INCLUDED_#if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    // L.h : header file
    ///////////////////////////////////////////////////////////////////////////////
    // L command targetclass L : public CCmdTarget
    {
    DECLARE_DYNCREATE(L) L();           // protected constructor used by dynamic creation// Attributes
    public:// Operations
    public:// Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(L)
    public:
    virtual void OnFinalRelease();
    //}}AFX_VIRTUAL// Implementation
    virtual ~L();
    protected:
    //virtual ~L(); // Generated message map functions
    //{{AFX_MSG(L)
    // NOTE - the ClassWizard will add and remove member functions here.
    //}}AFX_MSG DECLARE_MESSAGE_MAP()
    // Generated OLE dispatch map functions
    //{{AFX_DISPATCH(L)
    afx_msg void C();
    //}}AFX_DISPATCH
    DECLARE_DISPATCH_MAP()
    DECLARE_INTERFACE_MAP()
    };///////////////////////////////////////////////////////////////////////////////{{AFX_INSERT_LOCATION}}
    // Microsoft Visual C++ will insert additional declarations immediately before the previous line.#endif // !defined(AFX_L_H__D501315F_7DEA_4BDA_973E_9B286E6DC936__INCLUDED_)// L.cpp : implementation file
    //#include "stdafx.h"
    #include "VCEventClient.h"
    #include "L.h"#ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif/////////////////////////////////////////////////////////////////////////////
    // LIMPLEMENT_DYNCREATE(L, CCmdTarget)L::L()
    {
    EnableAutomation();
    }L::~L()
    {
    }
    void L::OnFinalRelease()
    {
    // When the last reference for an automation object is released
    // OnFinalRelease is called.  The base class will automatically
    // deletes the object.  Add additional cleanup required for your
    // object before calling the base class. CCmdTarget::OnFinalRelease();
    }
    BEGIN_MESSAGE_MAP(L, CCmdTarget)
    //{{AFX_MSG_MAP(L)
    // NOTE - the ClassWizard will add and remove mapping macros here.
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()BEGIN_DISPATCH_MAP(L, CCmdTarget)
    //{{AFX_DISPATCH_MAP(L)
    DISP_FUNCTION(L, "C", C, VT_EMPTY, VTS_NONE)
    //}}AFX_DISPATCH_MAP
    END_DISPATCH_MAP()// Note: we add support for IID_IL to support typesafe binding
    //  from VBA.  This IID must match the GUID that is attached to the 
    //  dispinterface in the .ODL file.// {D559D1C8-46B5-420A-8021-5E16442239B7}
    //static const IID IID_IL =
    //{ 0xd559d1c8, 0x46b5, 0x420a, { 0x80, 0x21, 0x5e, 0x16, 0x44, 0x22, 0x39, 0xb7 } };//static const GUID IID_IL = {0x000209f7,0x000,0x0000,{0xc0,0x00,0x0,0x00,0x00,0x00,0x00,0x46}}; 
    static const GUID IID_IL = {0xFFCB22E7,0x8FDA,0x49EC,{0x89,0xBB,0x13,0xD5,0x78,0x89,0x58,0x55}};BEGIN_INTERFACE_MAP(L, CCmdTarget)
    INTERFACE_PART(L, IID_IL, Dispatch)
    END_INTERFACE_MAP()/////////////////////////////////////////////////////////////////////////////
    // L message handlersvoid L::C() 
    {
    // TODO: Add your dispatch handler code here
    ::AfxMessageBox("sdfsdf");
    }编译,通过,哈哈!!!
    仔细研究代码,终于感觉有了点点眉目,于是写了开头的那两个动动!!!
    本来想再回过头来看看net中得,但是感觉俺知识又不够了,呵呵,参考文件如后附件。
    根据附件发现那篇<回调函数、消息和事件例程>好像有的地方不对,呵呵总结:其实事件关键是事件的函数指针与声明事件响应函数的类的指针!!!
          本来以为不需要声明事件响应函数的类的指针,
          但是后来发现欧错了。
          不过,发现“敏锐的观察与不断的努力”才是欧真正要学习的!!!
          
    有不对的地方,还请虾们指正,谢谢!!!                     LGX 20041220
      

  9.   

    附件:
    //******************************************************评C#事件处理 
    前几天学了一点C#,没当真的。因为要搞《MSDN开发精选》的缘故,完全不懂也说不过去。没看什么语言方面的书。也就是把Jefferey Richter的《Applied .NET Framework》(李建忠译本)找来翻翻。看到event那一部分就烦了,原来C#的delegate和event只是表面光,下面的实现还是非常笨重。一个长长的链表,里面放着闭包指针,类型是够安全了,付出的空间和时间效率都不小。对我我这种从C语言爬过来的人,就是觉得不爽。事件处理机制是C++及其后继者(Java、C#)的最大软肋之一。本质上是因为C++当年的选择,把对象之间的普通消息传递用成员函数调用给解决了。成员函数调用快是够快,但是导致了消息发送者与接受者之间的紧耦合。大多数情况下这倒也并不是什么大不了的事,偏偏在事件处理上,实践中需要松耦合,于是C++的问题就暴露出来了。君不见,所有用C++写的GUI Framework都在event这件事情上大做文章。比较笨的如MFC的全局映射表,比较聪明的如Qt的Signal/Slot,一个例外是VCL,Borland实现了closure指针,把caller context跟指针绑到一起发送给callee,Java比较中规中矩,按照最OO的方式实现了事件处理机制,但是可扩充性不好。C#的delegate其实就是VCL中closure指针的新版。总之是八仙过海,各显其能。但是我觉得,都是在C++已经走歪的老路上徒然努力。只要这个思路还在,事件处理就不可能非常elegant。C#可以让整件事情在表面上看起来很漂亮,可是骨子里还是邋遢的。就个人而言,我还是比较欣赏C的办法:规定一个协议,我把event数据准备好放在一个地方,然后就不管了,事件的接受者自己去取数据,自己解析,自己决定如何处理。这样的接受者,在对象分类中,叫做主动对象——active object。这两年在embedded system programming中间,大家越来越发现主动对象的种种优势。我个人觉得主流编程领域也应该考虑一下这个问题。主动对象的问题可能是类型不安全,但实际上类型安全没有那么重要, 没必要死抱住不放。原来C语言里:
    int (*compare)(); 
    声明的指针可以指向任何返回整数的函数,不管其参数列表如何。在C++里面,这个指针只能指向一个返回整数的无参函数了,灵活性大大降低。也难怪open source人士还是偏爱C。虽然安全性和灵活性同等重要,但是真正的黑客可以用自己的技术来保障安全性,却无法接受灵活性的缺失。扯远了。总之,看得越多,越觉得C真是一种伟大的语言,大概只有Fortran和LISP跟它处于同一级别。附带提一句,李建忠翻译的质量极高,令我辈叹服。 版权声明:CSDN是本Blog托管服务提供商。如本文牵涉版权问题,CSDN不承担相关责任,请版权拥有者直接与文章作者联系解决。发表于 2004年04月21日 1:56 PM 
    评论
    # 回复:评C#事件处理 2004-04-21 4:56 PM artpro 
    “就个人而言,我还是比较欣赏C的办法:规定一个协议,我把event数据准备好放在一个地方,然后就不管了,事件的接受者自己去取数据,自己解析,自己决定如何处理。” 这种事件传输的方式应该和C语言没有任何联系吧! 
    在OO中,同样可以这样做。 
    发送者甚至可以把一个包含一定行为的event传递给一个接收者。 
    接收者接到之后,不用自己解析,或者决定如何处理,只要调用event中的某一个接口,由event决定如何处理。 
    类似于Command模式。 
    这种方式是不是更优越一点? # 回复:评C#事件处理 2004-04-21 5:12 PM myan 
    不,Command模式不是一个好的解决方法——否则,为什么没有任何一个大型GUI Framework采用Command模式作为事件处理方法?关键在于,运用Command模式,caller可以把自己的context包装在object里,但是callee却只能调用cmd->execute(),无法把自己的数据传递给execute()。而事件处理不但需要caller的数据,也需要callee的数据。你也许会说,给execute()加一个参数不就行了?不行,因为那样的话,Caller就必须知道callee的类型,紧耦合又产生了 :-( 当然,消息传递的方式与语言无关,但是用C语言来做这件事情的时候,你会很自然地采用这种松耦合的方法,就是类似Win32 API的那种方法 :-) 所以我把功劳算在C上,呵呵,是有点故意模金的意思。 # 回复:评C#事件处理 2004-04-21 5:42 PM 韩磊 
    C运行效率高,开发效率对于我等懒人就无法忍受了。 # 回复:评C#事件处理 2004-04-21 5:52 PM artpro 
    Command类就是用来封装事件数据的啊!既可以封装caller的数据,也可以封装callee的数据啊! 例如,下面的Command: class ConcreateCommand 

    private: 
    int caller_data; 
    int callee_data; 
    public: 
    void SetCallerData(int i); 
    void SetCalleeData(int i); void Execute(); 
    }; callee调用时: cmd->SetCalleeData(xxx); 
    cmd->Execute(); 
    Command用来封装双方的数据,caller和callee之间松散耦合。 # 回复:评C#事件处理 2004-04-21 10:26 PM myan 
    呵呵,例子好看,却只能适用于最简单的情况,于实用无益。表面上看去是松耦合,实际上耦合得更紧密了。协约在接口之外,你设计时必须想清楚execute()中要用到哪些数据,各以何种方式映射到cmd对象中。这就已经不容易了。更何况还有很多时候,execute所需要了解的context,远不是几个数据那么简单。Callee可能要在不同状态下做出不同的判断和操作,因此需要提供不同的数据,这些如果都要事先预见到,你要花多大的智力代价?且不论你需要给Command写一大堆派生类。 GoF说,Command is object oriented style of callback。所以我们最好只把它当成callback来用。 # 回复:评C#事件处理 2004-04-22 10:02 AM artpro 
    Win32 API接受消息的函数。如: LRESULT WinProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); 就是应用程序传递给系统的一个callback函数,系统需要发送消息的时候回调这个callback。 
    wParam和lParam对于不同的事件,有不同的含义。这是发送者和接收者之间的约定。这类似于不同的Command子类对Command中封装的数据有不同的解释。 所以,在OO中,Command确实可以用来替代这个callback,作为消息传送的机制。耦合程度两者应该是相似的。 # 回复:评C#事件处理 2004-04-22 10:34 AM myan 
    呵呵,反了,兄弟。Command模式中caller是callback,Win32 API中,callee是callback,不一样的。请仔细考虑一下。 # 回复:评C#事件处理 2004-04-22 11:20 AM artpro 
    请看设计模式中的这段话,这里sender和receiver之间的关系和你说的caller和callee之间的关系应该是相似的吧: 5.12 Discussion of Behavioral Patterns The Command pattern supports decoupling by using a Command object to define the binding between a sender and receiver: 
    anInvoker(sender) anCommand aReceiver(receiver) 
    |             |         | 
    |----------Execute()--------->|----Action()------>| 
    |             |         | 
    The Command object provides a simple interface for issuing the request (that is, the Execute operation). Defining the sender-receiver connection in a separate object lets the sender work with different receivers. It keeps the sender decoupled from the receivers, making senders easy to reuse. Moreover, you can reuse the Command object to parameterize a receiver with different senders. The Command pattern nominally requires a subclass for each sender-receiver connection, although the pattern describes implementation techniques that avoid subclassing. ......哈哈,太长了,我补贴了,可以在网上找得到!!!!
      

  10.   

    // Managed C++ Extension
    __delegate void ClickEventHandler(int, double);
    __delegate void DblClickEventHandler(String*);__gc class EventSource {
             __event ClickEventHandler* OnClick;  
             __event DblClickEventHandler* OnDblClick;        // ...
    };// C++/CLI
    delegate void ClickEventHandler( int, double );
    delegate void DblClickEventHandler( String^ );ref class EventSource
    {
       event ClickEventHandler^ OnClick; 
       event DblClickEventHandler^ OnDblClick; 
    // ...
    };// Managed C++ Extension
    // 显式地实现add、remove和raise ...public __delegate void f(int);
    public __gc struct E {
       f* _E;
    public:
       E() { _E = 0; }   __event void add_E1(f* d) { _E += d; }   static void Go() {
          E* pE = new E;
          pE->E1 += new f(pE, &E::handler);
          pE->E1(17); 
          pE->E1 -= new f(pE, &E::handler);
          pE->E1(17); 
       }private:
       __event void raise_E1(int i) {
          if (_E)
             _E(i);
       }protected:
       __event void remove_E1(f* d) {
          _E -= d;
       }
    };// C++/CLI
    delegate void f( int );
    public ref struct E {
    private:
       f^ _E; //是的,委托也是引用类型public:
       E()
       {  // 注意0换成了nullptr!
          _E = nullptr; 
       }   // C++/CLI中显式事件声明的语法集合
       event f^ E1
       {
       public:
          void add( f^ d )
          {
             _E += d;
          }   protected:
          void remove( f^ d )
          {
             _E -= d;
          }   private:
          void raise( int i )
          {
             if ( _E )
                  _E( i );
          }   }
       static void Go()
       {
          E^ pE = gcnew E;
          pE->E1 += gcnew f( pE, &E::handler );
          pE->E1( 17 ); 
          pE->E1 -= gcnew f( pE, &E::handler );
          pE->E1( 17 ); 
       }
    };
      

  11.   

    jiangsheng(蒋晟.MSMVP2004Jan)  5星级战将牛,和和