1 概述
- 回調函數是一種編程模式,指的是將一個函數作為參數傳遞給另一個函數,并在某個特定事件發生時或滿足某些條件時由該函數調用。
- 這種機制允許你定義在特定事件發生時應執行的代碼,從而實現更靈活和模塊化的程序設計。
2 傳統C/C++回調實現方式
- 傳統C/C++實現回調,主要通過函數指針來實現。
- 有這樣一個場景,某業務系統需要檢測環境溫度,當溫度大于50度時進行告警,告警接口就可以作為回調函數,在溫度大于50度時調用。這里通過隨機生成一個溫度值,模式現實場景。
- 示例
-
#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表示式。- 基本語法
-
#include <functional>std::function<返回值類型(參數類型列表)> 函數對象;
-
- 示例
-
#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
是一個函數模板,用于將函數或成員函數與其參數綁定,生成一個新的可調用對象。- 基本語法
-
// 綁定非類成員函數/變量auto f = std::bind(可調用對象地址, 綁定的參數/占位符);// 綁定類成員函/變量auto f = std::bind(類函數/成員地址, 類實例對象地址, 綁定的參數/占位符);
-
- 示例
-
#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; // 輸出 15MyClass obj;// 綁定類成員函數auto boundMultiply = std::bind(&MyClass::multiply, &obj, std::placeholders::_1, std::placeholders::_2);std::cout << "Result: " << boundMultiply(3, 4) << std::endl; // 輸出 12system("pause");return 0;}
-
3.3 C++11實現回調
-
介紹完
std::function
和std::bind
再看下如何使用C++11語法實現回調。 -
回調函數為普通函數時示例
-
#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時示例
-
#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 已超閾值,告警 ...結束業務請按任意鍵繼續. . .
-
-
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;}