前言
學習回調函數,回調函數是通過函數指針或對象調用的函數。
回調函數就是通過函數指針或對象調用的函數,只要能一個函數能夠作為參數傳入並調用,這個函數就是回調函數。
#include <iostream>
int addCallBack(int a,int b){//回調函數
std::cout <<a+b<<std::endl;
return 0;
}
int main(int argc, char** argv) {
int(*p)(int,int);
p = addCallBack;
p(1,2);
return 0;
}
為什麼使用回調函數
前言裏直接在main函數調用addCallBack不是更直接嗎?為什麼要使用函數指針傳參給processData?
回調函數,通常是為了實現“控制反轉”(Inversion of Control), 靈活、分離、 異步與併發。
- 解耦和模塊化:
processData函數與具體的邏輯解耦,可以複用。
// 排序算法(不關心具體比較邏輯)
void sort(int* arr, int n, bool(*compare)(int, int)) {
for (int i = 0; i < n-1; i++) { //解耦和模塊化
for (int j = i+1; j < n; j++) {
if (compare(arr[i], arr[j])) {
std::swap(arr[i], arr[j]);
}
}
}
}
// 不同的比較策略
bool ascending(int a, int b) { return a > b; }
bool descending(int a, int b) { return a < b; }
int main() {
int data[] = {5, 2, 8, 1, 3};
sort(data, 5, ascending); // 升序
sort(data, 5, descending); // 降序
return 0;
}
- 異步處理:我不知道什麼時候能算完
#include <thread>
#include <functional>
#include <iostream>
// 模擬異步任務
void asyncTask(std::function<void(int)> callback) {
std::thread([callback]() {
std::this_thread::sleep_for(std::chrono::seconds(2));
int result = 42; // 模擬計算結果
callback(result); // 完成後通過回調通知
}).detach();
}
// 回調處理結果
void handleResult(int result) {
std::cout << "異步任務完成,結果: " << result << std::endl;
}
int main() {
std::cout << "開始異步任務..." << std::endl;
asyncTask(handleResult); // 非阻塞調用
// 主線程可以繼續做其他事情
for (int i = 0; i < 5; i++) {
std::cout << "主線程工作..." << i << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
return 0;
}
實現
函數指針實現
只能指向靜態函數或全局函數
// 含義:定義了一個名為 CallbackPtr 的類型
// 它是"指向返回void,接受兩個int參數的函數"的指針類型
// 1. typedef - 創建類型別名
// 2. void - 函數返回類型
// 3. (*CallbackPtr) - 指針名為 CallbackPtr
// 4. (int, int) - 函數接受兩個 int 參數
typedef void (*CallbackPtr)(int, int);
// C++11 的 using 語法(推薦)
// 與傳統 typedef 完全等價,但更清晰
using CallbackPtr_using = void(*)(int, int);
using namespace std;
//回調函數
void callback(int a,int b){
cout<<a+b<<endl;
}
void performTask(int a, int b, CallbackPtr cb) {
// 業務邏輯...
cb(a, b); // 執行回調
}
這裏其實就是使用指針調用函數。
void (*p)(int ,int);
p = callback;
//p = &callback;
(*p)(0,1);
//p(0,1);
Lambda表達式實現
- Lambda表達式語法
[捕獲列表](參數列表) mutable exception -> 返回類型 { 函數體 }
void run(std::function<void()> cb) { cb(); }
int main() {
int secret = 42;
// 使用 Lambda 作為回調,並捕獲局部變量 secret
run([secret]() {
std::cout << "數字是: " << secret << std::endl;
});
}
std::function 與 std::bind
C++11 引入的 std::function 是一個通用函數包裝器。它可以存儲、複製和調用任何“可調用對象”(函數指針、仿函數、Lambda、類成員函數
#include <functional>
class Downloader {
public:
void onFinished(int status) {
std::cout << "下載完成: " << status << std::endl;
}
};
int main() {
Downloader d;
// 綁定對象 d 到成員函數 onFinished
std::function<void(int)> cb = std::bind(&Downloader::onFinished, &d, std::placeholders::_1);
//std::placeholders::_1 這是一個佔位符。
//由於 onFinished(int status) 需要一個整數參數,但我們在綁定時還不知道這個參數的具體值(它要在未來觸發回調時才由調用者傳入)。
//_1 表示:這個位置的參數,請在未來調用 cb(value) 時,把第一個參數填到這裏。
cb(200);
}