C++中的回撥函式

海_纳百川發表於2024-10-15

回撥函式(callback function)是指作為引數傳遞給另一個函式的函式,在某個事件發生或某個任務完成時被呼叫。回撥函式在非同步程式設計中非常常見,因為它們允許程式碼在某個操作完成後自動執行某些行為,而無需阻塞程式。

回撥函式的基本特徵

  1. 作為引數傳遞:回撥函式通常是作為引數傳遞給另一個函式。
  2. 由呼叫者決定何時執行:回撥函式不會立即執行,而是由接受它的函式在適當的時候呼叫。
  3. 非同步程式設計的核心:在處理非同步操作時,例如網路請求、事件監聽或定時任務,回撥函式可以讓程式繼續執行其他程式碼,而不必等待某個操作完成。

在C++中,回撥函式通常是透過函式指標、std::function 或者基於類的回撥機制來實現的。以下是使用函式指標和std::function來實現回撥函式的兩個簡單例子。

1. 使用函式指標實現回撥函式

示例

#include <iostream>

// 定義一個函式,它接受一個回撥函式作為引數
void process(int x, void (*callback)(int)) {
    std::cout << "Processing number: " << x << std::endl;
    callback(x);  // 呼叫回撥函式
}

// 定義一個回撥函式
void printResult(int result) {
    std::cout << "Callback called with result: " << result << std::endl;
}

int main() {
    process(10, printResult);  // 將回撥函式傳遞給process函式
    return 0;
}

解釋:

  • process 函式接受兩個引數:一個整數和一個回撥函式。回撥函式的型別是 void (*callback)(int),表示它是一個返回型別為 void,引數為 int 的函式指標。
  • printResult 是回撥函式,當 process 函式完成它的主要任務後,它會呼叫 printResult

輸出:

Processing number: 10
Callback called with result: 10

2. 使用 std::function 實現回撥函式

C++11引入了 std::function,它更加靈活,可以接受函式指標、lambda表示式、或者類的成員函式作為回撥函式。

示例

#include <iostream>
#include <functional>

// 定義一個函式,它接受一個std::function作為回撥函式
void process(int x, const std::function<void(int)>& callback) {
    std::cout << "Processing number: " << x << std::endl;
    callback(x);  // 呼叫回撥函式
}

// 定義一個回撥函式
void printResult(int result) {
    std::cout << "Callback called with result: " << result << std::endl;
}

int main() {
    // 使用函式指標
    process(10, printResult);

    // 使用lambda表示式作為回撥
    process(20, [](int result) {
        std::cout << "Lambda called with result: " << result << std::endl;
    });

    return 0;
}

解釋:

  • process 函式現在接受一個 std::function<void(int)> 型別的回撥函式。這種方式比直接使用函式指標更加靈活。
  • 我們可以使用標準函式 printResult 作為回撥,也可以使用lambda表示式(匿名函式)作為回撥。

輸出:

Processing number: 10
Callback called with result: 10
Processing number: 20
Lambda called with result: 20

3. 使用類成員函式作為回撥

如果我們需要一個類的成員函式作為回撥,我們可以結合 std::functionstd::bind 或者直接使用 lambda 表示式。

示例

#include <iostream>
#include <functional>
#include <string>

class Processor {
public:
    void process(int x, const std::function<void(int)>& callback) {
        std::cout << "Processing number: " << x << std::endl;
        callback(x);
    }

    void memberCallback(int result) {
        std::cout << "Member callback called with result: " << result << std::endl;
    }
};

int main() {
    Processor p;

    // 使用類的成員函式作為回撥
    p.process(30, std::bind(&Processor::memberCallback, &p, std::placeholders::_1));

    // 或者直接使用lambda表示式
    p.process(40, [&](int result) {
        p.memberCallback(result);
    });

    return 0;
}

解釋:

  • std::bind 用於將類成員函式和具體物件繫結,這樣我們可以將成員函式作為回撥傳遞。std::placeholders::_1 表示佔位符,用於傳遞給回撥函式的引數。
  • 我們也可以直接使用 lambda 表示式來呼叫類的成員函式。

輸出:

Processing number: 30
Member callback called with result: 30
Processing number: 40
Member callback called with result: 40

總結

在C++中實現回撥函式有多種方式:

  1. 函式指標:最基礎的實現方式。
  2. std::function:從C++11開始的更靈活的回撥機制,支援lambda、函式指標、類成員函式等。
  3. 類的成員函式:透過std::bind 或 lambda 方式實現類的回撥函式。

std::function和lambda表示式更加靈活和現代化,適用於更多複雜的回撥場景。

相關文章