正如错误消息所说,您必须使用&StartHand::MouseButton
语法来获取指向成员函数 (ptmf) 的指针;这只是语言的一部分。
使用 ptmf 时,您正在调用的函数 glutMouseFunc 在这种情况下,也必须期望获得 ptmf 作为回调,否则使用非静态 MouseButton 将不起作用。相反,一种常见的技术是让回调与用户提供的void*
上下文(可以是实例指针)一起工作,但执行回调的库必须明确允许此参数。确保匹配外部库(下面的handle_mouse函数)期望的 ABI 也很重要。
由于 glut不允许用户提供上下文,因此您必须使用另一种机制:将您的对象与 glut 的当前窗口相关联。但是,它确实提供了一种获取“当前窗口”的方法,我已经使用它来将 avoid*
与窗口相关联。然后你只需要创建一个蹦床来进行类型转换并调用方法。
机械:
#include <map>
int glutGetWindow() { return 0; } // make this example compile and run ##E##
typedef std::pair<void*, void (*)(void*,int,int,int,int)> MouseCallback;
typedef std::map<int, MouseCallback> MouseCallbacks;
MouseCallbacks mouse_callbacks;
extern "C" void handle_mouse(int button, int state, int x, int y) {
MouseCallbacks::iterator i = mouse_callbacks.find(glutGetWindow());
if (i != mouse_callbacks.end()) { // should always be true, but possibly not
// if deregistering and events arrive
i->second.second(i->second.first, button, state, x, y);
}
}
void set_mousefunc(
MouseCallback::first_type obj,
MouseCallback::second_type f
) {
assert(obj); // preconditions
assert(f);
mouse_callbacks[glutGetWindow()] = MouseCallback(obj, f);
//glutMouseFunc(handle_mouse); // uncomment in non-example ##E##
handle_mouse(0, 0, 0, 0); // pretend it's triggered immediately ##E##
}
void unset_mousefunc() {
MouseCallbacks::iterator i = mouse_callbacks.find(glutGetWindow());
if (i != mouse_callbacks.end()) {
mouse_callbacks.erase(i);
//glutMouseFunc(0); // uncomment in non-example ##E##
}
}
例子:
#include <iostream>
struct Example {
void MouseButton(int button, int state, int x, int y) {
std::cout << "callback\n";
}
static void MouseButtonCallback(
void* self, int button, int state, int x, int y
) {
static_cast<Example*>(self)->MouseButton(button, state, x, y);
}
};
int main() {
Example obj;
set_mousefunc(&obj, &Example::MouseButtonCallback);
return 0;
}
请注意,您不再直接调用glutMouseFunc;它作为[un]set_mousefunc的一部分进行管理。
以防万一不清楚:我已经重写了这个答案,所以它应该对你有用,这样它就可以避免 C/C++ 链接问题被争论。它将按原样编译和运行(没有 glut),它应该与 glut 一起工作,只需稍作修改:注释或取消注释标记的 4 行##E##
。