C++ 回调函数详解

1、函数指针

概念

一个程序运行时,所有和运行相关的资源都需要被加载到内存中,如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。

使用函数指针实现函数调用

 1 #include <iostream>
 2  3 typedef void (*PINVOKE)(const char *str);
 4  5 void Invoke(const char *str)
 6 {
 7     std::cout << str << std::endl;
 8 }
 9 10 int main()
11 {
12     PINVOKE fp = Invoke;
13     fp("Hello world.");
14     
15     return 0;
16 }

说明

函数指针与函数声明的唯一区别就是用指针名(*fp)代替了函数名Invoke,然后进行赋值fp = Invoke就可以进行函数指针的调用了。声明函数指针时要求函数返回值类型、参数个数、参数类型等与已定义函数保持一致。注意,函数指针必须用括号括起来 void (*fp)(char *s)

2、回调函数

概念

声明并定义一个函数A,然后把函数A的指针作为参数传入其他的函数(或系统)中,其他的函数(或系统)在运行时通过函数指针调用函数A,这就是所谓的回调函数。简单来说:回调函数就是一个通过函数指针调用的函数。

示例

 1 #include <iostream>
 2  3 typedef void (*CALLBACKFUN)(const char *str);
 4  5 void PrintText(CALLBACKFUN fp, const char *str)
 6 {
 7     fp(str);
 8 }
 9 10 void Invoke(const char *str)
11 {
12     std::cout << str << std::endl;
13 }
14 15 int main()
16 {
17     PrintText(Invoke, "Hello world.");
18     return 0;
19 }

类成员函数作为回调函数

回调函数是基于C - Windows SDK的技术,不是针对C++的,程序员可以将一个C函数直接作为回调函数,但是如果试图直接使用C++的成员函数作为回调函数将发生错误,因为普通的C++成员函数都隐含一个传递函数作为参数,即this指针,C++通过向其他成员函数传递一个指向自身的指针来实现程序函数访问C++数据成员。所以实现类成员函数作为回调函数有两种途径:1、不使用成员函数(使用友元操作符friendC函数访问类的数据成员);2、使用静态成员函数。

例如:

 1 #include <iostream>
 2  3 class CPrintString
 4 {
 5 public:
 6     void PrintText(const char *str)
 7     {
 8         std::cout << str << std::endl;
 9     }
10     
11     static void SPrintText(void *pPs, const char *str)
12     {
13         CPrintString *pThis = static_cast<CPrintString *>(pPs);
14         if(NULL == pPs)
15         {
16             return;
17         }
18         pThis->PrintText(str);
19     }
20 };
21 22 typedef void (*PRINTTEXT)(void *pPs, const char *str);
23 24 void CallBackFun(void *pPs, const char *str, PRINTTEXT fp)
25 {
26     fp(pPs, str);
27 }
28 29 int main()
30 {
31     CPrintString obj;
32     CallBackFun((void *)&obj, "Hello world.", CPrintString::SPrintText);
33     
34     return 0;
35 }

3、为什么使用回调函数

一般情况下,回调函数能被普通函数替换,但回调函数最重要的作用是解耦,在这一特点上普通函数代替不了回调函数。

img

例子:

 1 #include <stdio.h>
 2 #include <softwareLib.h>     // 包含 Library Function 所在读得 Software library 库的头文件
 3  4 int Callback()              // Callback Function
 5 {
 6     // TODO
 7     return 0;
 8 }
 9 10 int main()                  // Main program
11 {
12     // TODO
13     Library(Callback);
14     // TODO
15     return 0;
16 }

乍一看,回调似乎只是函数间的调用,和普通函数调用没啥区别,但仔细一看,可以发现两者之间的一个关键的不同:在回调中,主程序把回调函数像参数一样传入库函数。这样一来,只要我们改变传进库函数的参数,就可以实现不同的功能,并且丝毫不需要修改库函数的实现,这就是解耦。再仔细看看,主函数和回调函数是在同一层的,而库函数在另外一层,一般情况下库函数对开发人员并不可见,库函数的实现一般不会被修改,也就是说不能通过修改库函数让库函数调用普通函数那样实现,那就只能通过传入不同的回调函数了,这在企业开发中非常常见。

posted @ 2021-11-18 16:00  HOracle  阅读(4080)  评论(0编辑  收藏  举报