1 概述
- 回调函数是一种编程模式,指的是将一个函数作为参数传递给另一个函数,并在某个特定事件发生时或满足某些条件时由该函数调用。
- 这种机制允许你定义在特定事件发生时应执行的代码,从而实现更灵活和模块化的程序设计。
2 传统C/C++回调实现方式
-
传统C/C++实现回调,主要通过函数指针来实现。
-
有这样一个场景,某业务系统需要检测环境温度,当温度大于50度时进行告警,告警接口就可以作为回调函数,在温度大于50度时调用。这里通过随机生成一个温度值,模式现实场景。
-
示例
*c#include <iostream> #include <stdlib.h> #include <time.h> // 定义函数指针 typedef void(*pCb)(int); void BusProcess(int tempera, pCb cb) { printf("开始业务\n"); printf("业务处理中\n"); // 处理业务过程中,如果温度值大于50摄氏度,则调用告警接口进行告警 if (tempera > 50) { cb(tempera); } printf("结束业务\n"); } // 定义回调函数 void temWarning(int tempera) { printf("温度值为: %d 已超阈值,告警 ...\n", tempera); } int main() { { srand(time(NULL)); // 随机生成温度值 int tempera = rand() % 100; // 开启业务 BusProcess(tempera, temWarning); } system("pause"); return 0; }
-
打印结果
*开始业务 业务处理中 温度值为: 65 已超阈值,告警 ... 结束业务 请按任意键继续. . .
3 C++11提供的回调新实现方式
- 介绍C++11实现回调前先介绍C++11提供的两个新接口
std::function
和std::bind
。
3.1 std::function
-
std::function
是一个通用的函数包装器,可以存储任何可调用对象,包括普通函数、类成员函数、仿函数、Lambda表示式。 -
基本语法
*c#include <functional> std::function<返回值类型(参数类型列表)> 函数对象;
-
示例
*c#include <iostream> #include <functional> // 普通函数 int add(int a, int b) { return a + b; } class Multiply { public: int operator()(int a, int b) { return a * b; } }; int main() { // 存储普通函数 std::function<int(int, int)> func1 = add; std::cout << "func1 result: " << func1(3, 4) << std::endl; // 存储 Lambda 表达式 std::function<int(int, int)> func2 = [](int a, int b) { return a - b; }; std::cout << "func2 result: " << func2(10, 3) << std::endl; // 存储函数对象 Multiply multiply; std::function<int(int, int)> func3 = multiply; std::cout << "func3 result: " << func3(5, 6) << std::endl; return 0; }
3.2 std::bind
-
std::bind
是一个函数模板,用于将函数或成员函数与其参数绑定,生成一个新的可调用对象。 -
基本语法
*c// 绑定非类成员函数/变量 auto f = std::bind(可调用对象地址, 绑定的参数/占位符); // 绑定类成员函/变量 auto f = std::bind(类函数/成员地址, 类实例对象地址, 绑定的参数/占位符);
-
示例
*c#include <iostream> #include <functional> int add(int a, int b) { return a + b; } class MyClass { public: int multiply(int a, int b) { return a * b; } }; int main() { // 绑定普通函数 auto boundAdd = std::bind(add, std::placeholders::_1, std::placeholders::_2); std::cout << "Result: " << boundAdd(5, 10) << std::endl; // 输出 15 MyClass obj; // 绑定类成员函数 auto boundMultiply = std::bind(&MyClass::multiply, &obj, std::placeholders::_1, std::placeholders::_2); std::cout << "Result: " << boundMultiply(3, 4) << std::endl; // 输出 12 system("pause"); return 0; }
3.3 C++11实现回调
-
介绍完
std::function
和std::bind
再看下如何使用C++11语法实现回调。 -
回调函数为普通函数时示例
c#include <iostream> #include <stdlib.h> #include <time.h> #include <functional> void BusProcess(int tempera, std::function<void(int)> op) { printf("开始业务\n"); printf("业务处理中\n"); // 处理业务过程中,如果温度值大于50摄氏度,则调用告警接口进行告警 if (tempera > 50) { op(tempera); } printf("结束业务\n"); } void temWarning(int tempera) { printf("温度值为: %d 已超阈值,告警 ...\n", tempera); } int main() { { srand(time(NULL)); // 随机生成温度值 int tempera = rand() % 100; // 开启业务,调用对象为普通函数 BusProcess(tempera, temWarning); } system("pause"); return 0; }
-
打印结果
开始业务 业务处理中 温度值为: 56 已超阈值,告警 ... 结束业务 请按任意键继续. . .
-
回调函数为类成员对象、函数对象、Lambda时示例
c#include <iostream> #include <stdlib.h> #include <time.h> #include <functional> void BusProcess(int tempera, std::function<void(int)> op) { printf("开始业务\n"); printf("业务处理中\n"); // 处理业务过程中,如果温度值大于50摄氏度,则调用告警接口进行告警 if (tempera > 50) { op(tempera); } printf("结束业务\n"); } class MyWarn { public: void startWarning(int tempera) { printf("温度值为: %d 已超阈值,告警 ...\n", tempera); } void operator()(int tempera) { printf("operator() 温度值为: %d 已超阈值,告警 ...\n", tempera); } }; int main() { { srand(time(NULL)); // 随机生成温度值 int tempera = rand() % 100; MyWarn mwarn; std::function<void(int)> fc = std::bind(&MyWarn::startWarning, &mwarn, std::placeholders::_1); // 调用对象为类成员函数 BusProcess(tempera, fc); MyWarn mwarn2; std::function<void(int)> fc2 = mwarn2; // 调用对象为仿函数 BusProcess(tempera, fc2); // 调用对象为Lambda表达式 BusProcess(tempera, [](int te) { printf("Lambda 温度值为: %d 已超阈值,告警 ...\n", te); }); } system("pause"); return 0; }
-
打印结果
开始业务 业务处理中 温度值为: 66 已超阈值,告警 ... 结束业务 开始业务 业务处理中 operator() 温度值为: 66 已超阈值,告警 ... 结束业务 开始业务 业务处理中 Lambda 温度值为: 66 已超阈值,告警 ... 结束业务 请按任意键继续. . .
c
class MyWarn {
public:
void startWarning(int tempera) {
printf("温度值为: %d 已超阈值,告警 ...\n", tempera);
}
};
#include <iostream>
#include <string>
#include <vector>
#include <stdlib.h>
#include <time.h>
#include <functional>
class myPersion {
public:
myPersion(): mCode(1001), mName("Jack") {
}
void setCode(int code) {
std::cout << "code: " << code << std::endl;
mCode = code;
}
private:
int mCode;
std::string mName;
};
typedef void(*pCb)(int);
void optFunc(int data, pCb cb) {
printf("optFunc ...\n");
if (data % 2 == 0) {
cb(data);
}
}
void optFunc2(int data, std::function<void(int)> op) {
printf("optFunc2 ...\n");
if (data % 2 == 0) {
op(data);
}
}
void onHandle(int data) {
printf("onHandle ...\n");
}
int main() {
{
srand(time(NULL)); // 初始化随机数生成器
int radNum = rand() % 100;
printf("radNum: %d\n", radNum);
optFunc(radNum, onHandle);
myPersion mp;
//optFunc(1001, &mp.setCode);
}
{
srand(time(NULL)); // 初始化随机数生成器
int radNum = rand() % 100;
printf("radNum: %d\n", radNum);
optFunc2(radNum, onHandle);
optFunc2(radNum, [](int x) {
printf("lam ...\n");
});
myPersion mp;
std::function<void(int)> fc = std::bind(&myPersion::setCode, &mp, std::placeholders::_1);
optFunc2(10010, fc);
}
system("pause");
return 0;
}