zoukankan      html  css  js  c++  java
  • [转]你会使用回调函数吗?

    之所以以反问的形式提出这个问题,是因为以我的观点来看,“回调函数”对一个C/C++程序员来说是很平常的,一些API的使用,一些接口的设计均要用到回调函数的概念。但是我面试过的一些有“多年工作经验”的C系程序员,共事过的一些“有经验”的同事竟然对回调函数不了解,更别提使用了。那今天我就以我的理解来梳理一下回调函数的概念和使用场景。

    什么是回调函数?

    维基百科释义:

    在计算机程序设计中,回调函数,或简称回调(Callback),是指通过函数参数传递到其它代码的,某一块可执行代码的引用。这一设计允许了底层代码调用在高层定义的子程序。

    不好理解吧?那举个生活中常见的例子:你在网上买了东西通过快递来配送,给你两个选择:
    1. 你可以一遍遍的打快递配送公司的电话,查询你的货是否到了,是否可以领取;
    2. 你可以安心的干自己的事,等配送人员把货送到你家门口打电话通知你,你去领取;
    你会选择哪种方式处理?当然你会选择第二钟处理方式,好处不言而喻,这也正是回调函数的形象解释。

    回调函数的实现原理

    对于C/C++语言来说就是将函数指针作为参数传递给其它函数。

    回调函数实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #include <iostream>
    using namespace std;
    void Sum(int a, int b)
    {
        int c = a + b;
        cout << "Sum = " << c << endl;
    }
    typedef void (*FuncCallBack)(intint);
    void GetCallBack(const int i, FuncCallBack cb)
    {
        if (1 == i)
        {
            cb(3, 4);
        }
    }
    void main()
    {
        GetCallBack(1, Sum);
        system("pause");
    }

    运行结果:Sum = 7  ,对于上面这个例子FuncCallBack就是回调函数的定义,Sum是其实现

    另外,在C++的接口设计里常常会遇到这种情况:需要向类接口中注册很多不同的回调函数,这样这些回调函数的定义和管理便比较杂乱,这样我们可以借用delegate类的概念来这么实现回调。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    #include <iostream>
    using namespace std;
    class IEvent
    {
    public:
        virtual void Test1(int i) = 0;
        virtual void Test2(int i) = 0;
        virtual void Test3(int i) = 0;
    };
    class TestEvent:public IEvent
    {
    public:
        void Test1(int i) { cout << "Test1 : " << i << endl;}
        void Test2(int i) { cout << "Test2 : " << i << endl;}
        void Test3(int i) { cout << "Test3 : " << i << endl;}
    private:
        int p;
    };
    class NotifyEvent
    {
    public:
        void Run(int flag)
        {
            switch(flag)
            {
            case 1:
                testEvent_->Test1(1);
                break;
            case 2:
                testEvent_->Test2(2);
                break;
            case 3:
                testEvent_->Test3(3);
                break;
            default:
                break;
            }
        }
        void SetMyEvent(IEvent* testEvent) {testEvent_ = testEvent;}
    private:
        IEvent* testEvent_;
    };
    int _tmain(int argc, _TCHAR* argv[])
    {
        IEvent* ptr_event = new TestEvent;
        NotifyEvent notifyEvent;
        notifyEvent.SetMyEvent(ptr_event);
        notifyEvent.Run(1);
        notifyEvent.Run(3);
        system("pause");
        return 0;
    }

    运行结果:Test1 : 1    Test3 : 3

    对于接口使用者而言,暴露出了IEvent这个接口,回调的管理都在这个接口中,避免了上述管理杂乱的情况。

    本文出自 “永远的朋友” 博客,请务必保留此出处http://yaocoder.blog.51cto.com/2668309/1221422

  • 相关阅读:
    MFC和Qt优缺点 (MFC几乎没有优点、全面下风)
    获得WIN7管理员权限(可通过修改注册表,或者组策略改变)
    tolua#是Unity静态绑定lua的一个解决方案
    C#实现拼图游戏
    FastDFS分布式文件系统
    生成动态Lambda表达式1
    Azure IoT
    SignalR
    延迟队列功能
    监控知识体系
  • 原文地址:https://www.cnblogs.com/willbin/p/3190404.html
Copyright © 2011-2022 走看看