在 C++ 中,函數指針(Function Pointer) 是一個特殊的指針變量,它存儲的是函數在內存中的起始地址,而不是數據變量的地址。

1. 基本語法

聲明函數指針的關鍵在於:指針的特徵標(返回類型和參數列表) 必須與它指向的函數完全匹配。

語法模板: 返回類型 (*指針變量名)(參數列表);

示例代碼:

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

// 聲明一個指向返回 int,參數為兩個 int 的函數的指針
int (*funcPtr)(int, int); 

// 賦值
funcPtr = add; 

// 調用(兩種方式等價)
int result = funcPtr(5, 3);   // 像普通函數一樣使用
int result2 = (*funcPtr)(5, 3); // 顯式解引用

示例1:

//函數指針
void add(int num1, int num2) {
	printf("num1 + num2 = %d\n", num1 + num2);
}

void sub(int num1, int num2) {
	printf("num1 - num2 = %d\n", num1 - num2);
}

// 方法指針,傳兩個數
void operate(void(*method)(int, int), int num1, int num2) {
	method(num1, num2);
}

int main() {

	// 方法指針怎麼定義? 方法的返回(*方法的名稱)(方法的參數)
	// 方法指針怎麼定義? return_type (*pointer_name)(parameter_types);

	// 定義一個函數指針
	//void (*func_p)(int, int) = add;
	//// 通過函數指針調用函數
	//func_p(10, 20);

	operate(add, 10, 20);
	operate(sub, 10, 20);
	return 0;
}

輸出:

num1 + num2 = 30                                                                                                        
num1 - num2 = -10

示例2:

// 定義回調函數類型
typedef void(*CompressCallback)(int progress);

//void compressData(void(*callback)(int)){
void compressData(CompressCallback callback) { //兩種寫法一致,typedef 更清晰 
	// 模擬數據壓縮過程
	for (int i = 0; i <= 100; i += 20) {
		// 模擬一些處理時間
		// 調用回調函數,傳遞當前進度
		callback(i);
	}
}

// 回調函數實現
void onCompressProgress(int progress) {
	printf("壓縮的進度是: %d%%\n", progress);
}

int main() {
	// 啓動數據壓縮,並傳入回調函數
	compressData(onCompressProgress);
	return 0;
}

輸出:

壓縮的進度是: 0%                                                                                                        
壓縮的進度是: 20%                                                                                                       
壓縮的進度是: 40%                                                                                                       
壓縮的進度是: 60%                                                                                                       
壓縮的進度是: 80%                                                                                                       
壓縮的進度是: 100%

2. 為什麼要用函數指針?

函數指針的主要用途是將“邏輯”作為參數傳遞。

  • 回調函數 (Callbacks):當某個事件發生時,調用預先指定的函數。
  • 實現多態性:在 C 語言或底層 C++ 中,可以用函數指針模擬對象的多態行為。
  • 排序與搜索: 例如 std::qsort,你可以傳入不同的比較邏輯。

3. 更現代的替代方案

雖然傳統的函數指針在底層開發中依然重要,但在現代 C++ (C++11 及以後) 中,通常推薦使用更安全、更強大的工具:

工具

描述

std::function

一個通用的函數包裝器,可以持有函數指針、Lambda 表達式、成員函數等。

Lambda 表達式

允許在原地定義匿名函數,通常比單獨寫一個函數更簡潔。

typedefusing

用於簡化複雜的函數指針聲明,提高可讀性。

簡化示例:

C++

// 使用 using 別名
using MathOp = int(*)(int, int);
MathOp op = add;

// 使用 std::function (推薦)
#include <functional>
std::function<int(int, int)> modernPtr = add;

4. 注意事項

  1. 括號必不可少: int *f(int) 聲明的是一個返回 int*函數;而 int (*f)(int) 聲明的是一個函數指針
  2. 類型檢查:函數指針不會進行隱式類型轉換,參數和返回值必須嚴格一致。
  3. 類成員函數: 指向類成員函數的指針語法更復雜(需要使用 &ClassName::FunctionName),通常建議配合 std::bind 或 Lambda 使用。