回調函數本質是「函數指標作為參數傳遞」,由被調用者在特定事件/條件觸發時反向調用。核心流程:
非靜態成員函數擁有隱含的 this 指標,其型別為 Ret (Class::*)(Args...),與普通函數指標 Ret (*)(Args...) 型別不兼容,且調用時需提供物件實例。直接傳遞 &MyClass::memberFunc 給期望函數指標的 API 會編譯失敗。
靜態成員函數沒有 this,型別退化為普通函數指標,可直接作為回調。但靜態函數無法直接訪問非靜態成員,需通過額外參數傳入物件指標。
// 1. 定義回調函數型別
typedef void (*CallbackFunc)(void* userData);
// 2. 類定義
class MyClass {
public:
// 靜態回調入口(符合函數指標型別)
static void staticCallback(void* userData) {
// 3. 將 userData 轉回 this,調用真實非靜態邏輯
MyClass* self = static_cast<MyClass*>(userData);
self->realCallback();
}
// 真實業務邏輯(非靜態)
void realCallback() {
cout << "實例回調觸發,this=" << this << endl;
}
// 註冊回調給外部 API
void registerCallback() {
extern void SetCallback(CallbackFunc cb, void* data);
SetCallback(staticCallback, this); // 傳入 this 作為 userData
}
};
// 外部 API 模擬
void SetCallback(CallbackFunc cb, void* data) {
// 事件觸發時調用
cb(data);
}
若 API 支援 std::function 或可修改為模板,可直接使用 Lambda 捕獲 this,無需靜態中轉,代碼更簡潔、型別安全。
#include <functional>
class ModernClass {
public:
using Callback = std::function<void()>;
void registerCallback(Callback cb) {
// 直接存儲或轉發
storedCallback_ = cb;
}
void trigger() {
if (storedCallback_) storedCallback_();
}
private:
Callback storedCallback_;
};
// 使用範例
ModernClass obj;
obj.registerCallback([&obj]() { obj.memberFunc(); }); // 或 [this]() { this->memberFunc(); }
obj.trigger();
#include <functional>
obj.registerCallback(std::bind(&MyClass::memberFunc, &obj));
| 維度 | API (正向調用) | 回調 (逆向調用) |
|---|---|---|
| 提供方 | 底層/庫 | 上層/應用 |
| 調用方 | 上層 | 底層 |
| 函數知名度 | 編譯期已知 | 運行期由上層「安裝」 |
| 機制 | 直接呼叫 | 底層保存函數指標,事件觸發時間接調用 |
static 成員函數 + void* userData 模式。std::function + Lambda,支援捕獲上下文,避免強轉。shared_ptr + weak_ptr 防止循環引用。掌握這兩種模式,即可優雅地將 C++ 物件導向設計與基於函數指標的回調機制完美融合。