C++ 回調函數的幾種策略


Stackoverflow中提出了這樣一個問題:假設我們實現了一個User類,Library類,現在Library類中utility需要回調User中func方法,總結答案,常見的幾種方法如下:

  1. 靜態方法:將User類中func方法實現為靜態方法,Library類中進行調用。
  2. 虛擬方法:將User類繼承至基類Base,Base類中func方法為純虛函數。
  3. 直接回調:在Library中保存User類指針,utility方法中直接調用。

下面則是非常規方法。

基於tag dispatch的調用方法,利用空類實現標簽回調,在注冊方法時提供不同的空類模板參數實現不同的調用,代碼如下:

template<class T>
struct tag_t {
    using type = T;
    constexpr tag_t() {}
};

struct ForLibrary;
template <class T> class Library {
public: 
    T *node = nullptr;
    
    Library(T *n):node(n) {}

    void utility() {
        func(tag_t<ForLibrary>(),node);
    };
};

class User {
public:
    void func() {
        cout << "User::func" << endl;
    }

    friend void func(tag_t<ForLibrary>, User *self) {
        self->func();
    }
};

不得不說,這種方法太妙了,既可以動態變化回調方法(只需修改ForLibrary參數)又無需改變User類實現,而且一切都是靜態調用無虛函數開銷。

利用模板基類實現靜態多態機制,通過在基類中強轉類型調用子類方法,實現路由回調,代碼如下:

#include <iostream>
#include <functional>

template<typename T>
class ICallback {
public:
  void callback() {
    static_cast<T*>(this)->func();
  }
};

class User : public ICallback<User> 
{
public:
  
  void func(){
    std::cout << "User::func" << std::endl;
    }
};

template<class T,class F=std::function<void(void)>>
class Library {
private:
  T *node;
public:
  Library(T* n):node(n) {
  }

  void utility()
  {
    std::mem_fn(&T::callback)(*node);
  }

  void utility(F func) {
    func();
  }

};


int main()
{
  User user;
  Library<User> lib(&user);
  lib.utility();
  lib.utility(std::bind(&User::callback,user));

  return 0;
}

回調類與實現類相互解耦又能避免虛函數多態。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM