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

在 C++ 中實現 C# 風格的 Delegate 機制

     編輯:關於C++

背景動機

C# 的 delegate(委託)提供了優雅的事件通知機制。在 C++ 中雖可用回調函數、消息傳遞實現類似功能,但傳統回調對面向對象支持較弱(難以綁定成員函數)。本文展示如何用模板實現類型安全、面向對象的 Delegate。

基礎實現:無參數無返回值

class Delegate {
public:
    virtual ~Delegate() {}
    virtual void operator()() = 0;
};

template <typename C>
class DelegateImpl : public Delegate {
    typedef void (C::*F)();
    C* m_class;
    F m_fun;
public:
    DelegateImpl(C* c, F f) : m_class(c), m_fun(f) {}
    virtual void operator()() {
        if (m_class) (m_class->*m_fun)();
    }
};

使用示例

class Sdk {
public:
    Delegate* pEvent;
    Sdk() : pEvent(nullptr) {}
    void DoSomething() {
        cout << "opened" << endl;
        if (pEvent) (*pEvent)();
    }
};

class Client {
    Sdk m_sdk;
public:
    Client() {
        m_sdk.pEvent = new DelegateImpl<Client>(this, &Client::OnOpen);
    }
    void OnOpen() { cout << "event fired" << endl; }
};

進階:宏定義支持多參數、返回值

為支持不同參數個數,定義宏 DEFINE_DELEGATE 自動生成對應的 Delegate 類、實現類及工廠函數:


// 0 參數
#define DEFINE_DELEGATE(NAME, R) \
class NAME##Delegate { \
public: \
    virtual ~NAME##Delegate() {} \
    virtual R operator()() = 0; \
}; \
template <typename C> \
class NAME##DelegateImpl : public NAME##Delegate { \
    typedef R (C::*F)(); \
    C* m_class; F m_fun; \
public: \
    NAME##DelegateImpl(C* c, F f) : m_class(c), m_fun(f) {} \
    virtual R operator()() { \
        if (m_class) return (m_class->*m_fun)(); \
    } \
}; \
template <typename C, typename F> \
NAME##Delegate* Make##NAME##Delegate(C* c, F f) { \
    return new NAME##DelegateImpl<C>(c, f); \
}

// 1 參數、2 參數版本類似,只需在參數列表中添加 P1, P2...

使用宏定義的 Delegate

DEFINE_DELEGATE(Open, void, int, string)

class Sdk {
public:
    OpenDelegate* pEvent;
    Sdk() : pEvent(nullptr) {}
    void Open() {
        cout << "opened" << endl;
        if (pEvent) (*pEvent)(100, "你好");
    }
};

class Client {
    Sdk m_sdk;
public:
    Client() {
        m_sdk.pEvent = MakeOpenDelegate(this, &Client::OnOpen2);
    }
    void OnOpen2(int t, string str) {
        cout << "event fired, Param = " << t << " param2 = " << str << endl;
    }
};

局限與改進方向

  • 內存管理:示例中用 new 創建 Delegate,需手動 delete,建議改用智能指針(std::unique_ptr/std::shared_ptr)
  • 參數數量固定:宏需為每種參數個數單獨定義,C++11 可用可變參數模板統一實現
  • 無對象生命週期綁定:若綁定對象已銷毀,調用會導致未定義行為,可引入弱引用機制
  • 性能:虛函數調用有微小開銷,高性能場景可考慮 std::function + lambda 或 FastDelegate 庫

現代 C++ 替代方案

C++11 起推薦使用 std::function<R(Args...)> 配合 std::bind 或 lambda,標準庫實現更完善、類型安全且無需宏:

#include <functional>

class Sdk {
public:
    std::function<void(int, string)> onOpen;
    void Open() {
        if (onOpen) onOpen(100, "你好");
    }
};

class Client {
    Sdk m_sdk;
public:
    Client() {
        m_sdk.onOpen = [this](int t, string s) { OnOpen2(t, s); };
    }
    void OnOpen2(int t, string s) { /* ... */ }
};

總結

本文展示了從基礎虛函數+模板到宏擴展的 Delegate 實現演進,幫助理解 C++ 實現「可調用對象」的核心思想。實際項目中優先選用 C++11 標準庫設施。

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