zoukankan      html  css  js  c++  java
  • C++回调函数的理解与使用

    一、回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。 
    回调函数机制: 
    1、定义一个函数(普通函数即可); 
    2、将此函数的地址注册给调用者; 
    3、特定的事件或条件发生时,调用者使用函数指针调用回调函数。 
    注:为什么要特定事件或条件发生?不应该随时都可以调用回调函数吗? 
    以下是回调函数的两种使用方式(简单理解): 
    1、

    #include <stdio.h>
    typedef int(*callback)(int,int);
    
    int add(int a,int b,callback p){
        return (*p)(a,b);
    }
    
    int add(int a,int b){
        return a+b;
    }
    int main(int argc,char *args[]){
        int res = add(4,2,add);
        printf("%d
    ",res);
        return 0;
    }

    在这个例子中,可以看到,我们定义了一个callbak的函数指针,参数为两个int,返回值为int,通过调用函数地址来进行简单的相加运算。 
    2、

    #include <stdio.h>
    typedef int (callBack)(const void *buffer,size_t size,char *p_out);
    
    void callFunc(callBack *consume_bytes, char *p_out) {
        printf("callFunc
    ");
        const void *buffer = NULL;
        consume_bytes(buffer,0,p_out); //传入值可以随便填
    }
    
    int callBackFunc(const void *buffer, size_t size, char *p_out){
        printf("callBackFunc
    ");
        memset(p_out,0x00,sizeof(char)*100);
        strcpy(p_out,"encoderCallback:this is string.");
        return 1;
    }
    
    int main(int argc,char *args[]){
        char p_out[100];
        callFunc(callBackFunc,p_out);
        printf("%s
    ",p_out);
        return 0;
    }

    可以把回调函数和调用函数封装承类再调用。

    二、在理解“回调函数”之前,首先讨论下函数指针的概念。

    函数指针

    (1)概念:指针是一个变量,是用来指向内存地址的。一个程序运行时,所有和运行相关的物件都是需要加载到内存中,这就决定了程序运行时的任何物件都可以用指针来指向它。函数是存放在内存代码区域内的,它们同样有地址,因此同样可以用指针来存取函数,把这种指向函数入口地址的指针称为函数指针。

    (2)先来看一个Hello World程序:

    int main(int argc,char* argv[])
    {
    printf("Hello World! ");
    return 0;
    }

           然后,采用函数调用的形式来实现:

    复制代码
    void Invoke(char* s);

    int main(int argc,char* argv[])
    {
    Invoke("Hello World! ");
    return 0;
    }

    void Invoke(char* s)
    {
    printf(s);
    }
    复制代码

          用函数指针的方式来实现:

    复制代码
    void Invoke(char* s);

    int main()
    {
    void (*fp)(char* s); //声明一个函数指针(fp)
    fp=Invoke; //将Invoke函数的入口地址赋值给fp
    fp("Hello World! "); //函数指针fp实现函数调用
    return 0;
    }

    void Invoke(char* s)
    {
    printf(s);
    }
    复制代码

          由上知道:函数指针函数的声明之间唯一区别就是,用指针名(*fp)代替了函数名Invoke,这样这声明了一个函数指针,然后进行赋值fp=Invoke就可以进行函数指针的调用了。声明函数指针时,只要函数返回值类型、参数个数、参数类型等保持一致,就可以声明一个函数指针了。注意,函数指针必须用括号括起来 void (*fp)(char* s)。

         实际中,为了方便,通常用宏定义的方式来声明函数指针,实现程序如下:

    复制代码
    typedef void (*FP)(char* s);
    void Invoke(char* s);

    int main(int argc,char* argv[])
    {
    FP fp; //通常是用宏FP来声明一个函数指针fp
    fp=Invoke;
    fp("Hello World! ");
    return 0;
    }

    void Invoke(char* s)
    {
    printf(s);
    }
    复制代码

    函数指针数组

          下面用程序对函数指针数组来个大致了解:

    复制代码
    #include <iostream>
    #include <string>
    using namespace std;

    typedef void (*FP)(char* s);
    void f1(char* s){cout<<s;}
    void f2(char* s){cout<<s;}
    void f3(char* s){cout<<s;}

    int main(int argc,char* argv[])
    {
    void* a[]={f1,f2,f3}; //定义了指针数组,这里a是一个普通指针
    a[0]("Hello World! "); //编译错误,指针数组不能用下标的方式来调用函数

    FP f[]={f1,f2,f3}; //定义一个函数指针的数组,这里的f是一个函数指针
    f[0]("Hello World! "); //正确,函数指针的数组进行下标操作可以进行函数的间接调用

    return 0;
    }
    复制代码

    回调函数

    (1)概念:回调函数,顾名思义,就是使用者自己定义一个函数,使用者自己实现这个函数的程序内容,然后把这个函数作为参数传入别人(或系统)的函数中,由别人(或系统)的函数在运行时来调用的函数。函数是你实现的,但由别人(或系统)的函数在运行时通过参数传递的方式调用,这就是所谓的回调函数。简单来说,就是由别人的函数运行期间来回调你实现的函数。

    (2)标准Hello World程序:

    int main(int argc,char* argv[])
    {
    printf("Hello World! ");
    return 0;
    }

          将它修改成函数回调样式:

    复制代码
    //定义回调函数
    void PrintfText()
    {
    printf("Hello World! ");
    }

    //定义实现回调函数的"调用函数"
    void CallPrintfText(void (*callfuct)())
    {
    callfuct();
    }

    //在main函数中实现函数回调
    int main(int argc,char* argv[])
    {
    CallPrintfText(PrintfText);
    return 0;
    }
    复制代码

          修改成带参的回调样式:

    复制代码
    //定义带参回调函数
    void PrintfText(char* s)
    {
    printf(s);
    }

    //定义实现带参回调函数的"调用函数"
    void CallPrintfText(void (*callfuct)(char*),char* s)
    {
    callfuct(s);
    }

    //在main函数中实现带参的函数回调
    int main(int argc,char* argv[])
    {
    CallPrintfText(PrintfText,"Hello World! ");
    return 0;
    }
    复制代码
     

          至此,对回调函数应该有了一个大致的了解。

                                  改变自己,从现在做起-----------久馆

                                                                              

  • 相关阅读:
    每日一水 POJ8道水题
    编译和使用 MySQL C++ Connector
    j2ee model1模型完成分页逻辑的实现 详解!
    DB查询分析器访问EXCEL时,要在表名前后加上中括弧或双引号
    指向结构体变量的指针
    EOSS V3.0 企业运营支撑系统(基于RBAC原理的权限管理)
    MybatisGen1.0 Mybatis JavaBean Mapper生成工具
    The table name must be enclosed in double quotation marks or sqare bracket while accessing EXCEL by
    资源-Android:Android
    软件-开发软件:Android Studio
  • 原文地址:https://www.cnblogs.com/zzw19940404/p/14152151.html
Copyright © 2011-2022 走看看