C++ 回调函数学习笔记(从入门到理解)
一、什么是回调函数(Callback)
1. 一句话理解
把一个函数“交给别人”,在合适的时候由别人调用,这就是回调。
你写函数,不自己主动调,而是让别人帮你在某个时机执行。
二、生活中的理解
外卖例子
你点外卖时:
你对平台说:
到了给我打电话。
这个“打电话”动作就是你提供的回调函数。
你不需要一直问外卖到了没
外卖到了平台会主动调用你留的“通知函数”
三、本质定义
回调 =函数指针 / 可调用对象+被其他函数调用
公式:
把函数A作为参数 传给函数B 由函数B在某个时机调用函数AA:回调函数
B:触发回调的函数
四、最基础回调(函数指针)
示例1
#include <iostream> using namespace std; void hello() { cout << "我是回调函数" << endl; } void execute(void (*cb)()) { cout << "先做自己的事..." << endl; cb(); // 调用回调 } int main() { execute(hello); }输出
先做自己的事... 我是回调函数分析
这个:
void (*cb)()是函数指针。
意思:
cb 是一个指针 指向参数为空 返回void的函数拆开理解
普通函数:
void hello();函数指针:
void (*p)();赋值:
p = hello;调用:
p();图解
hello ---> 函数地址 ↓ p ↓ p();五、带参数回调
#include <iostream> using namespace std; void printSum(int a,int b) { cout<<a+b<<endl; } void calc(void (*cb)(int,int)) { cb(3,5); } int main() { calc(printSum); }输
8六、为什么需要回调
不用回调
任务完成 然后自己主动去检查轮询(低效)
用回调
任务完成 系统自动通知你事件驱动(高效)
常见场景
按钮点击
Qt:
connect(button, &QPushButton::clicked, this, &MainWindow::onClick);点击按钮:
onClick()就是回调。
七、C风格回调(函数指针)
经典写法:
void doWork(void (*callback)()) //void (*callback)()是一个函数函数指针 { //任务完成 callback(); }优点:
快
简单
缺点:
只能传普通函数
不灵活
八、C++现代回调 std::function
这个比函数指针高级很多。
头文件
#include <functional>写法
function<void()>意思:
返回 void 参数为空 可调用对象示例
#include <iostream> #include <functional> using namespace std; void test() { cout<<"hello"<<endl; } void run(function<void()> cb) { cb(); } int main() { run(test); }和函数指针对比
函数指针:
void (*cb)()现代写法:
function<void()> cb更像:
装任何能调用的东西的容器九、function 能装什么
1 普通函数
run(test);2 Lambda
run([](){ cout<<"lambda"; });3 仿函数
class Functor { public: void operator()() { cout<<"仿函数"; } }; run(Functor());三者都能回调
普通函数 Lambda 函数对象这就是现代 C++ 强大之处。
十、Lambda做回调(最常用)
#include <iostream> using namespace std; void work(function<void()> cb) { cout<<"处理中..."<<endl; cb(); } int main() { work([](){ cout<<"处理完成"; }); }输出
处理中... 处理完成十一、带状态的回调
函数指针做不到:
我要回调还能带变量Lambda可以:
int x=10; auto cb=[x]() { cout<<x; };输出
10这叫:捕获变量
十二、异步回调思想
下载文件 下载完通知我伪代码:
download(url, [](){ cout<<"下载完成"; });是不是很像:
事件发生 触发回调十三、回调本质图
你写函数 ↓ 交给系统 ↓ 事件发生 ↓ 系统调用你的函数就是回调。
十四、回调 vs 普通函数调用
普通调用
main └── hello()你主动调。
回调
main └── system └── hello()系统替你调。
十五、回调常见面试题
Q1 什么是回调
答:
将函数作为参数传递 由其他函数在特定时机调用Q2 回调实现方式
函数指针
std::function
lambda
仿函数
成员函数绑定
Q3 函数指针和function区别
| 对比 | 函数指针 | std::function |
|---|---|---|
| 普通函数 | 支持 | 支持 |
| lambda | 有限 | 支持 |
| 仿函数 | 不方便 | 支持 |
| 灵活性 | 低 | 高 |
| 现代C++ | 较少 | 常用 |
结论:
现代开发优先 std::function十六、手写一个回调框架
#include <iostream> #include <functional> using namespace std; class Task { private: function<void()> callback; public: void setCallback(function<void()> cb) { callback=cb; } void run() { cout<<"任务执行中..."<<endl; if(callback) callback(); } }; int main() { Task t; t.setCallback([](){ cout<<"任务完成回调"; }); t.run(); }输出
任务执行中... 任务完成回调十八、记忆口诀
自己调用叫函数调用 别人调用叫回调十九、⭐核心代码模板⭐
传统函数指针模板
void callback() { } void run(void (*cb)()) { cb(); } int main() { run(callback); }现代模板
#include <functional> using namespace std; void run(function<void()> cb) { cb(); } int main() { run([](){ }); }二十、容易混淆的几个概念
回调 vs 函数指针
不是一个东西。
函数指针只是:
实现回调的一种方式回调 vs Lambda
Lambda不是回调。
Lambda可以作为回调回调 vs 异步
不是一回事:
异步常用回调通知结果
回调不一定异步
二十一、总结
回调本质
把函数交出去 让别人以后调用实现方式
函数指针 std::function lambda 仿函数现代推荐:
std::function + lambda二十二、最后一句理解回调
不是我去调用函数 而是我把函数留给系统 等系统回来调用我这就是回调。
