一个选择,如果你真的想避免多态函数包装器几乎不重要的开销,是使这些函数静态并让它们采用“用户数据”void*
参数,指向函数是成员的类的适当实例的。在静态函数内部,您然后转换回适当的类型:
#include <iostream>
struct A{
typedef void (*callback_type)(void*, int);
callback_type callback;
void* user_data;
void set_callback(callback_type cb, void* ud){
callback = cb; user_data = ud;
}
void invoke(){ callback(user_data, 42); }
};
struct B{
static void cb_foo(void* vself, int data){
B* self = static_cast<B*>(vself);
self->foo(data);
}
void foo(int data){ std::cout << data * 2 << "\n"; }
};
struct C{
static void cb_bar(void* vself, int data){
C* self = static_cast<C*>(vself);
self->bar(data);
}
void bar(int data){ std::cout << data / 2 << "\n"; }
};
int main(){
A a;
B b;
a.set_callback(&B::cb_foo, &b);
a.invoke();
C c;
a.set_callback(&C::cb_bar, &c);
a.invoke();
}
Ideone 上的实时示例。
不过,我个人建议使用std::function
,因为上述内容在可以接受为回调的方面受到严重限制。std::function
是一个多态函数包装器,这意味着它可以采用普通函数指针、成员函数指针甚至函子(函数对象)并以相同的方式调用它们。与std::bind
允许您将参数绑定到函数的 一起,您可以轻松地回调成员函数。Boost 也提供了它们(Boost.Function,Boost.Bind)。
#include <iostream>
#include <functional> // C++11
//#include <boost/function.hpp>
//#include <boost/bind.hpp>
struct A{
std::function<void(int)> callback;
void invoke(){ callback(42); }
};
struct B{
void foo(int data){ std::cout << data * 2 << "\n"; }
};
struct C{
void bar(int data){ std::cout << data / 2 << "\n"; }
};
int main(){
using namespace std::placeholders; // namespace for argument placeholders for std::bind
// not needed for Boost.Bind
A a;
B b;
a.callback = std::bind(&B::foo, &b, _1);
a.invoke();
C c;
a.callback = std::bind(&C::bar, &c, _1);
a.invoke();
};
Ideone 上的实时示例。
基本上std::bind
会自动完成您在第一个版本中必须手动执行的操作,它保存对象指针并调用其上的成员函数。但是,它不是通过void*
指针来执行此操作的,而是std::bind
为每个不同的对象指针返回不同的绑定器类型。这就是你需要的原因std::function
,因为它不在乎你传递了什么。