博客 / 詳情

返回

【C++】回調函數

前言

學習回調函數,回調函數是通過函數指針或對象調用的函數。

回調函數就是通過函數指針或對象調用的函數,只要能一個函數能夠作為參數傳入並調用,這個函數就是回調函數。

#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);
}
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.