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

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

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

下面則是很是規方法。ios

基於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類實現,並且一切都是靜態調用無虛函數開銷。this

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

#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;
}

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

相關文章
相關標籤/搜索