【C++11 回調函數】回調入門(一)


在理解“回調函數”之前,首先討論下函數指針的概念。

一、函數指針概述

指針是一個變量,是用來指向內存地址的。一個程序運行時,所有和運行相關的物件都是需要加載到內存中,這就決定了程序運行時的任何物件都可以用指針來指向它。函數是存放在內存代碼區域內的,它們同樣有地址,因此同樣可以用指針來存取函數,把這種指向函數入口地址的指針稱為函數指針。


下面是個使用函數指針的例子:

#include <iostream>

// 也可以用宏定義的方式來聲明函數指針
// typedef int (*fp)(int, int);

int testFun(int a, int b) {
	return a + b;
}

int main() {
	// 定義一個函數指針fp,初始化指向testFun函數
	int (*fp)(int, int) = testFun;
	// 通過函數指針fp,調用testFun函數
	int sum = fp(1, 2);
	std::cout << sum << std::endl; // 輸出:3

	return 0;
}

由上知道:函數指針與函數的聲明之間唯一區別就是,用指針名(*fp)代替了函數名 testFun,這樣這聲明了一個函數指針,然后進行賦值fp=testFun就可以進行函數指針的調用了。下面可以討論需要用到函數指針的回調函數了。

二、回調函數概述

如果你把函數的指針(地址)作為參數傳遞給另一個函數,當這個指針被用來調用其所指向的函數時,我們就說這是回調函數。回調函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用於對該事件或條件進行響應。

回調函數的機制如下:

  • 定義一個回調函數;
  • 提供函數實現的一方在初始化的時候,將回調函數的函數指針注冊給調用者;
  • 當特定的事件或條件發生的時候,調用者使用函數指針調用回調函數對事件進行處理。

三、回調函數的意義

因為可以把調用者與被調用者分開,所以調用者不關心誰是被調用者。它只需知道存在一個具有特定原型和限制條件的被調用函數。簡而言之,回調函數就是允許用戶把需要調用的函數的指針作為參數傳遞給一個函數,以便該函數在處理相似事件的時候可以靈活的使用不同的方法。下面看幾個應用:

  • 回調可用於通知機制。比如要寫一個多線程下載器,需要顯示下載進度,在另外的下載線程類中下載好了文件時,此時不方便也不允許直接調用進度條界面的刷新進度值函數,這時候就需要將刷新進度值函數設置為回調函數了,作為下載線程中調用者函數的參數,執行調用者函數就相當於執行回調函數,就可以刷新界面的進度值了。
  • 另一個使用回調機制的 API 函數是 EnumWindow(),它枚舉屏幕上所有的頂層窗口,每個窗口都可以通過它調用另一個程序提供的函數,並傳遞窗口的處理程序。例如:如果被調用者返回一個值,就繼續進行迭代;否則,退出。EnumWindow() 並不關心被調用者在何處,也不關心被調用者用它傳遞的處理程序做了什么,它只關心返回值,因為基於返回值,它將繼續執行或退出。
  • 還有圖形界面客戶端常用 事件循環 (event loop) 有條不紊的處理用戶輸入/計時器/系統處理/跨進程通信 等事件,一般采用回調響應事件。

注意:不管怎么說,回調函數是繼承自C語言的。在 C++ 中,應只在與C代碼建立接口或與已有的回調接口打交道時,才使用回調函數。除了上述情況,在 C++ 中應使用虛擬方法或仿函數(functor),而不是回調函數。

四、用函數指針實現回調函數

不帶參回調函數的示例如下:

#include <iostream>

// 定義不帶參回調函數
void callbackFun() {
	std::cout << "This is callbackFun";
}

// 定義參數為回調函數的調用者(一般在其它系統或子線程中)
void callbackExec(void (*fp)()) {
	return fp();
}

int main() {
	// 當特定的事件或條件發生的時候,調用者調用回調函數callbackFun
	callbackExec(callbackFun); // 輸出:"This is callbackFun"

	return 0;
}

帶參回調函數:

#include <iostream>

// 定義帶參回調函數
int callbackFun(int a, int b) {
	return a + b;
}

// 定義參數為回調函數的"調用函數"
int callbackExec(int (*fp)(int, int), int a, int b) {
	return fp(a, b);
}

int main() {
	// 運行時執行"調用函數",調用回調函數callbackFun
	int sum = callbackExec(callbackFun, 1, 2);
	std::cout << sum << std::endl; // 輸出:3

	return 0;
}

參考:

關於C/C++的回調函數!不知道的注意了!

知乎 - C/C++回調函數



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM