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

回调类与实现类相互解耦又能避免虚函数多态。

posted on 2017-05-25 18:15  kkford  阅读(4597)  评论(0编辑  收藏  举报

导航