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

C++ 委託、信號與槽機制實現:從回呼函式到橋接委託的演進

     編輯:關於C++

問題背景:庫與客戶端的反向呼叫

函式庫常需通知客戶端事件 (如網路封包到達、UI 點擊)。傳統方案:

  1. 繼承+虛擬函式:客戶端繼承基底類別並覆寫 OnRecv()。缺點:強迫繼承、多重繼承麻煩、難以動態切換處理邏輯。
  2. 回呼函式指標:void (*OnRecvHandle)()。缺點:型別不安全、無法綁定成員函式/仿函式。

委託模式與橋接委託

委託本質:型別安全的動態訊息轉發機制。Java/C# 內建支援,C++ 需自行實現。核心難點:如何儲存任意可呼叫實體 (函式指標、仿函式、成員函式) 並統一呼叫。

橋接委託架構


// 介面層:統一呼叫入口
struct DelegationInterface {
    virtual ~DelegationInterface() {}
    virtual void Action() = 0;
};

// 實作層:模板適配具體接收者
template <class T>
struct DelegationImpl : public DelegationInterface {
    T functor_;
    DelegationImpl(T f) : functor_(f) {}
    virtual void Action() { functor_(); }  // 統一呼叫 operator()
};

// 信號類別:管理連線與觸發
struct Signal {
    DelegationInterface* impl_ = nullptr;
    ~Signal() { delete impl_; }
    void operator()() { if (impl_) impl_->Action(); }

    template <class T>
    void ConnectSlot(T slot) {
        delete impl_;
        impl_ = new DelegationImpl<T>(slot);
    }
};

使用範例:


struct Socket { Signal OnRecv; };

void OnRecvFunc() { /* ... */ }
struct Functor { void operator()() { /* ... */ } };

Socket s;
s.OnRecv.ConnectSlot(OnRecvFunc);      // 綁定函式
s.OnRecv.ConnectSlot(Functor());       // 綁定仿函式
s.OnRecv();  // 觸發

支援成員函式的進階橋接


template <class T>
struct DelegationImpl : public DelegationInterface {
    using MemFn = void (T::*)();
    T* obj_;
    MemFn fn_;
    DelegationImpl(T* o, MemFn f) : obj_(o), fn_(f) {}
    virtual void Action() { if (obj_) (obj_->*fn_)(); }
};

struct Signal {
    DelegationInterface* impl_ = nullptr;
    // ...
    template <class T>
    void ConnectSlot(T& obj, void (T::* fn)()) {
        delete impl_;
        impl_ = new DelegationImpl<T>(&obj, fn);
    }
};

// 使用
struct MsgBox { void Show() { /* ... */ } };
MsgBox box;
Socket s;
s.OnRecv.ConnectSlot(box, &MsgBox::Show);

多重委託 (Multicast)

將 impl_ 改為 std::vector<DelegationInterface*>,ConnectSlot 推入向量,operator() 迴圈呼叫所有槽位。

參數化委託的挑戰

C++ 模板無法直接支援可變參數委託,需為每種參數組合撰寫獨立介面/實作 (如 DelegationInterface<P1>, DelegationInterface<P1,P2>)。解決方案:

  • 參數打包結構體 / std::tuple (C++11)
  • 巨集產生重複程式碼
  • Qt MOC 預處理器擴充語法
  • Boost.Signals2 / C++20 std::function + 可變參數模板

結語

橋接委託以「介面隔離細節、模板適配型別、多型統一呼叫」實現型別安全的動態綁定。雖參數化仍受限於模板機制,但現代 C++ (Boost, C++17/20) 已提供成熟解決方案。理解其原理有助於設計靈活的事件系統。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved