C ++ in several ways to implement callback mechanism (a total of three methods, plus three kinds)

Transfer: http://www.cnblogs.com/weiym/archive/2012/08/28/2660053.html

Brief introduction

A callback function usually occurs in two roles (the caller and implementer), when we want an event occurs, the caller's call implementation-defined. As a provider Framework, it provides a framework for the entire program when certain events occur need to call a behavior, and specific definition of these acts are done by the customer, the customer may choose different behaviors for different events (realized dynamic call function is running), so the caller can not be displayed by calling a specific function name. To solve this problem, call call through a function pointer, just implementers own definition of the function passed as a parameter to the caller can be. Your function is implemented, but by someone else (or system) function at run-time parameters are passed by way calling, which is called the callback function. Simply put, run by the others to function during the callback function you achieve.

(1) Callback way

Callback nature is set into a function pointer, then call the method when needed needed to trigger an event, such as Windows window message processing function is of this type.

void fun1(int a)
{
    cout << a << endl;
}

void fun2(int a)
{
    cout << a*a << endl;
}

void caller(void(*f)(int),int a)   //调用者提供接口,具体的实现由客户自己实现
{
    f(a);
}

int main()
{
    int a;
    cin >> a;
    if (a > 0)    //当a>0时,调用fun1
        caller(fun1, a);
    else          //当a<=0时,调用fun2
        caller(fun2, a);
    return 0;
}

(2) Sink manner

Sink essence is that you achieve in accordance with the other requirements of a C ++ interface, and then you implement the interface settings to each other, call each other when the interface is required to trigger an event, COM connection point is living in this way.

Download the file above requirements, if implemented Sink, code is as follows:

class IDownloadSink
{
public:
    virtual void OnDownloadFinished(const char* pURL, bool bOK) = 0;
};
class CMyDownloader
{
public:
    CMyDownloader(IDownloadSink* pSink)
        :m_pSink(pSink)
    {
    }

    void DownloadFile(const char* pURL)
    {
        cout << "downloading: " << pURL << "" << endl;
        if(m_pSink != NULL)
        {
            m_pSink->OnDownloadFinished(pURL, true);
        }
    }

private:
    IDownloadSink* m_pSink;
};

class CMyFile: public IDownloadSink
{
public:
    void download()
    {
        CMyDownloader downloader(this);
        downloader.DownloadFile("www.baidu.com");
    }

    virtual void OnDownloadFinished(const char* pURL, bool bOK)
    {
        cout << "OnDownloadFinished, URL:" << pURL << "    status:" << bOK << endl;
    }
};

(3) Delegate way

Delegate essence is to set up member function pointers to each other, and then let the other party to call when you need a trigger event.
C # using Delegate way to achieve Event, so that C ++ programmers very envious, because the relationship between the C ++ language itself, to achieve Delegate is still very troublesome.
The example above we implemented Delegate in the following way:

class CDownloadDelegateBase
{
public:
    virtual void Fire(const char* pURL, bool bOK) = 0;
};

template<typename O, typename T>
class CDownloadDelegate: public CDownloadDelegateBase
{
    typedef void (T::*Fun)(const char*, bool);
public:
    CDownloadDelegate(O* pObj = NULL, Fun pFun = NULL)
        :m_pFun(pFun), m_pObj(pObj)
    {
    }
    
    virtual void Fire(const char* pURL, bool bOK)
    {
        if(m_pFun != NULL
            && m_pObj != NULL)
        {
            (m_pObj->*m_pFun)(pURL, bOK);
        }
    }

private:
    Fun m_pFun;
    O* m_pObj;
};

template<typename O, typename T>
CDownloadDelegate<O,T>* MakeDelegate(O* pObject, void (T::*pFun)(const char* pURL, bool))
{
    return new CDownloadDelegate<O, T>(pObject, pFun);
}

class CDownloadEvent
{
public:
    ~CDownloadEvent()
    {
        vector<CDownloadDelegateBase*>::iterator itr = m_arDelegates.begin();
        while (itr != m_arDelegates.end())
        {
            delete *itr;
            ++itr;
        }
        m_arDelegates.clear();
    }

    void operator += (CDownloadDelegateBase* p)
    {
        m_arDelegates.push_back(p);
    }

    void operator -= (CDownloadDelegateBase* p)
    {
        ITR itr = remove(m_arDelegates.begin(), m_arDelegates.end(), p);

        ITR itrTemp = itr;
        while (itrTemp != m_arDelegates.end())
        {
            delete *itr;
            ++itr;
        }
        m_arDelegates.erase(itr, m_arDelegates.end());
    }

    void operator()(const char* pURL, bool bOK)
    {
        ITR itrTemp = m_arDelegates.begin();
        while (itrTemp != m_arDelegates.end())
        {
            (*itrTemp)->Fire(pURL, bOK);
            ++itrTemp;
        }
    }

private:
    vector<CDownloadDelegateBase*> m_arDelegates;
    typedef vector<CDownloadDelegateBase*>::iterator ITR;
};


class CMyDownloaderEx
{
public:
    void DownloadFile(const char* pURL)
    {
        cout << "downloading: " << pURL << "" << endl;
        downloadEvent(pURL, true);
    }

    CDownloadEvent downloadEvent;
};

class CMyFileEx
{
public:
    void download()
    {
        CMyDownloaderEx downloader;
        downloader.downloadEvent += MakeDelegate(this, &CMyFileEx::OnDownloadFinished);
        downloader.DownloadFile("www.baidu.com");
    }

    virtual void OnDownloadFinished(const char* pURL, bool bOK)
    {
        cout << "OnDownloadFinished, URL:" << pURL << "    status:" << bOK << endl;
    }
};

Delegate can see the way the code than the other two above most of the way, and above us is the number of fixed parameters and the type of implementation, if you want to achieve variable parameters, to be more trouble and more.
The reference variable parameters of these two ways to achieve:
Yet Another Class in the Delegate the -style C # C ++ Standard
Member Function Pointers and The Fastest Possible C ++ Delegates

We can use the following code to test our implementation above:

int _tmain(int argc, _TCHAR* argv[])
{

    DownloadFile("www.baidu.com", OnDownloadFinished);

    CMyFile f1;
    f1.download();

    CMyFileEx ff;
    ff.download();

    system("pause");

    return 0;
}

Finally, a simple comparison of the callback method to achieve the above three kinds:
The first method is Callback process-oriented, flexible and easy to use, as the C language itself.
Sink The second method is object-oriented, more use in C ++, you can enclose a group in a callback interface Sink in for a series of relatively fixed callback.
A third method is Delegate object-oriented, and a different set of interfaces Sink package, the package is a Delegate function units, the particle size is smaller and more flexible than the Sink.

You prefer what way to implement callback?

Guess you like

Origin blog.csdn.net/QIJINGBO123/article/details/89150889