回调函数
文章目录
- 回调函数
- 一、函数指针
- 二、回调函数
- 应用
- Reference
一、函数指针
指针是一个变量,是用来指向内存地址。
一个程序运行时,所有和运行相关的东西都需要加载到内存当中,因此可以通过指针指向该内存。
函数是存放在内存代码区域内的,函数名就是函数地址,把这种指向函数入口地址的指针称为函数指针。
Example:
#include <iostream>
typedef int (*fp)(int, int);
int Sum(int lhs, int rhs) {
return lhs + rhs;
}
int Minus(int lhs, int rhs) {
return lhs - rhs;
}
int main() {
int (*randy)(int, int);
randy = Sum;
std::cout << randy(2, 13) << std::endl; // 输出:15
fp sesame = Minus;
std::cout << sesame(22, 1) << std::endl; // 输出:21
return 0;
}
可以通过 typedef 的方式简化操作 typedef int (*fp)(int, int);
,也可以直接定义一个函数指针 int (*randy)(int, int);
二、回调函数
当我们把指针作为函数参数时,可以获取该指针所对应的那块内存。
如果这个指针是函数指针,就可以调用该函数的方法进行处理,这个被调用的具体处理的函数就是回调函数。
从上面的例子可以看出来,同一个函数指针,可以指向不同的函数实现,因此可以针对不同的场景,传入不同的函数,而调用方根本不用修改代码。
这就是回调函数灵活的地方,调用者根本不用关注函数如何实现的,只需要关注何时调用即可。
回调函数的使用方法:
-
定义一个回调函数;
-
调用者在使用时,保存回调函数的函数指针,称为“注册”;
-
调用者发现条件满足时,使用函数指针调用回调函数对事件进行处理。
-
回调可用于通知机制。比如要写一个多线程下载器,显示下载进度时可以将进度值函数设置为函数,线程内部即可处理,非常方便。
回调函数是继承自C语言的。一般C语言没有多态,所以通过设置回调函数或者钩子函数,达到同样的函数调用不同实现函数的目的。
应用
带参回调函数:
#include <iostream>
// 定义带参回调函数
int callbackFun(int lhs, int rhs) {
return lhs + rhs;
}
// 定义参数为回调函数的"调用函数"
int callbackRandy(int (*fp)(int, int), int lhs, int rhs) {
return fp(lhs, rhs);
}
int main() {
// 运行时执行"调用函数",调用回调函数callbackFun
int sum = callbackRandy(callbackFun, 2, 13);
std::cout << sum << std::endl; // 输出:3
return 0;
}
类的静态成员函数和非静态成员函数
#include <iostream>
class Randy {
public:
void R1_Non_Static() {
std::cout << "call function R1_Non_Static" << std::endl;
}
static void R2_Static() {
std::cout << "call function R2_Static" << std::endl;
}
};
class Sesame {
public:
void Ses_call1(void (*callBack)()) {
std::cout << "call function Ses_call1" << std::endl;
callBack();
}
void Ses_call2(void (Randy::*callBack)(), void *object) {
std::cout << "call function Ses_call2" << std::endl;
((Randy *)object->*callBack)();
}
};
int main(int argc, char **argv) {
Randy randy;
Sesame sesame;
sesame.Ses_call2(&Randy::R1_Non_Static, &randy);
sesame.Ses_call1(Randy::R2_Static);
}
结果:
call function Ses_call2
call function R1_Non_Static
call function Ses_call1
call function R2_Static
上面Ses_call2
有个缺陷,就是实现里调用了Randy
类,鲁棒性不强,因此可以增加1层包装:
#include <iostream>
class Randy {
public:
void R1_Non_Static() {
std::cout << "call function R1_Non_Static" << std::endl;
}
static void R2_Static() {
std::cout << "call function R2_Static" << std::endl;
}
// 包装函数
static void Wrapper(void *objectR) {
std::cout << "call function Wrapper" << std::endl;
reinterpret_cast<Randy *>(objectR)->R1_Non_Static();
}
};
class Sesame {
public:
void Ses_call1(void (*callBack)()) {
std::cout << "call function Ses_call1" << std::endl;
callBack();
}
void Ses_call2(void (Randy::*callBack)(), void *object) {
std::cout << "call function Ses_call2" << std::endl;
((Randy *)object->*callBack)();
}
// 针对包装函数的调用
void Ses_call3(void (*callBack)(void *), void *objectS) {
std::cout << "call function Ses_call3" << std::endl;
callBack(objectS);
}
};
int main(int argc, char **argv) {
Randy randy;
Sesame sesame;
sesame.Ses_call2(&Randy::R1_Non_Static, &randy);
sesame.Ses_call1(Randy::R2_Static);
sesame.Ses_call3(&Randy::Wrapper, &randy);
}
运行结果:
call function Ses_call2
call function R1_Non_Static
call function Ses_call1
call function R2_Static
call function Ses_call3
call function Wrapper
call function R1_Non_Static
Reference
- 关于C++ 回调函数(callback) 精简且实用
- 【C++11 回调函数】回调入门(一)
欢迎关注公众号【三戒纪元】