【发布时间】:2016-05-31 01:24:55
【问题描述】:
假设我们有一些像这样的 C 风格 API:
void register_callback(target, callback_function);
,其中target 是某种对象,例如一个服务器,call_back 必须是一个函数指针。
现在我们要适应(更准确地说,添加一个包装层。我们无法访问底层 C 代码,因为它是一个第三方库)这个 API 到 C++。我们想要 OOP,所以我们把目标变成了一个类:
class Target {
Target(): target() { register_callback(target, callback_function_member) }
private:
target_t target;
void callback_function_member (param_t parameter) { /* a set of things to do with the members */ }
// other members
}
我们可能想让回调成为上面的成员函数,因为它(在某些情况下)与实例密切相关。但这行不通。没有办法将成员函数改编为函数指针(参见,例如Pointers to Member Functions)。
我在互联网上找到的所有解决方案(包括上一个)都只处理只有一个实例负责这项工作的情况。在那里我们可以专门编写一个包装函数(参见1)或一个包装类的静态函数。
问题是,如果我们想要多个实例,而且还要动态创建它们怎么办?您可以为每个实例编写一个包装函数或类,例如
Target *pTarget;
void wrapper(param_t parameter) {
pTarget->callback_function_member(parameter);
}
int main() {
Target myTarget();
pTarget = &myTarget();
myTarget.register(wrapper);
// some work
return 0;
}
但是您不能为每个动态创建的实例手动编写函数。而且似乎不可能将任何类型的信息传递给全局函数(例如,将实例存储在全局容器中,但是在调用时如何传递索引?)。
std::bind 接近解决方案(我不知道它的存在),但关键问题是std::bind 的返回值不能转换为函数指针。使用target<type_of_function_pointer>() 的std::function 得到nil,因为类型不匹配。当我假装它是一个函数指针并直接传递它时,就会发生段错误。
这可能吗?还是我的目标被误导了?处理这个问题的规范方法是什么?
【问题讨论】:
-
通常这将使用
void*来完成,回调函数会将其作为参数。您的注册函数还需要获取此指针并存储它,以便在调用它时将其传递给回调函数。 -
这可能很简单:将回调设为接收
void * instance的静态成员。在其中,将其转换回this并用它调用私人成员。要注册,只需注册this并回调。 -
@Benjamin Lindley,@user3528438,实际上库是 libuv,API 是
int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb)。不知道是不是我用错了。 -
这是一个改编自另一个问题的已删除答案的演示。也许它有帮助。 ideone.com/6sCsdV
-
@user3528438,在搜索
void*和“libuv”后,我发现在文档中存在需要传入this的位置,即uv_stream_t的data。
标签: c++ c callback function-pointers member-functions