首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C/C++ 中 Callback 機制的三種實現模式

     編輯:關於C語言

Callback 本質

註冊「函數 + 參數」,在滿足條件時自動調用。核心難點:參數多樣性與統一介面的矛盾——調用方不關心具體參數,只需呼叫統一的 Run()。

方案一:C++ 模板類型擦除(類型安全,但模板膨脹)

class Closure {
public:
    virtual ~Closure() {}
    virtual void Run() = 0;
protected:
    Closure() {}
};

template <class T>
class Callback0 : public Closure {
    typedef void (T::*Done)();
    T* object_; Done run_;
public:
    Callback0(T* obj, Done run) : object_(obj), run_(run) {}
    void Run() override { (object_->*run_)(); }
};

template <class T, class T1>
class Callback1 : public Closure {
    typedef void (T::*Done)(T1);
    T* object_; Done run_; T1 arg0_;
public:
    Callback1(T* obj, Done run, T1 arg) : object_(obj), run_(run), arg0_(arg) {}
    void Run() override { (object_->*run_)(arg0_); }
};

// 輔助工廠函數
template <class T> Closure* NewCallback(T* obj, void (T::*m)()) {
    return new Callback0<T>(obj, m);
}
template <class T, class T1> Closure* NewCallback(T* obj, void (T::*m)(T1), T1 p) {
    return new Callback1<T, T1>(obj, m, p);
}

優點:型別安全、參數編譯期綁定。
缺點:模板程式碼膨脹、閱讀負擔大、C 語言難以移植。

方案二:C++ 繼承介面分離參數與回調(CEGUI 風格)

  • 基類 Event 定義 virtual void fireEvent(EventArgs*)
  • 不同參數派生自 EventArgs(如 MouseEventArgs、KeyEventArgs)
  • 調用端統一:event->fireEvent(args)

優點:無模板、符合 OOP 多態、易於 C 語言移植。

方案三:C 語言函數指針 + void* 參數包裝

typedef struct event {
    void (*fireEvent)(void* arg);
    void* arg;
} event_t;

typedef struct event_arg1 { int value; } event_arg1_t;

void fireEvent_arg1(void* arg) {
    event_arg1_t* a = (event_arg1_t*)arg;
    printf("arg 1 = %d\n", a->value);
}

#define NewEvent(event, eventtype, callback) do { \
    *(event) = malloc(sizeof(event_t)); \
    (*(event))->arg = malloc(sizeof(eventtype)); \
    (*(event))->fireEvent = callback; \
} while(0)

#define DestroyEvent(event) do { \
    free((*(event))->arg); free(*(event)); \
} while(0)

int main() {
    event_t* event;
    NewEvent(&event, event_arg1_t, fireEvent_arg1);
    ((event_arg1_t*)event->arg)->value = 100;
    event->fireEvent(event->arg);
    DestroyEvent(&event);
    return 0;
}

優點:純 C 實現、零模板、跨語言呼叫友好。
缺點:型別安全靠程序員自覺、需手動管理記憶體。

選型建議

場景推薦方案
現代 C++、追求型別安全方案一或 std::function/lambda (C++11+)
C++ 專案、偏好 OOP、避免模板方案二
純 C 專案、嵌入式、需跨語言方案三
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved