如何将C++类成员方法作为SDL_EventFilter传递?
解决SDL2中无法将类成员函数注册为SDL_EventFilter的问题
问题原因
C++类的非静态成员函数会隐式携带一个this指针,导致它的函数签名和SDL_EventFilter要求的C风格函数指针不匹配——SDL_EventFilter的签名是int (*)(void*, SDL_Event*),而非静态成员函数的实际签名是int (Game::*)(void*, SDL_Event*),两者无法直接转换,强制转换会导致运行时this指针缺失,触发未定义行为。
解决方案:使用静态成员函数+用户数据传递
最安全且符合封装原则的做法是把事件处理函数改成静态成员函数,然后利用SDL_AddEventWatch的第二个参数(用户数据)传递Game类的实例指针,在静态函数内部转换回Game*后再调用成员逻辑。
步骤1:修改OnResize为静态成员函数
在Game类的声明中添加static关键字,实现时也保持静态:
// Game类头文件声明 class Game { // ... 其他成员 ... static int OnResize(void* data, SDL_Event* event); // ... 其他成员 ... }; // 实现文件 int Game::OnResize(void* data, SDL_Event* event) { if (event->type == SDL_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_RESIZED) { // 将用户数据转换为Game实例指针 Game* game = static_cast<Game*>(data); // 调用Game的成员方法 game->SetScale(); game->states[game->state]->OnResize(*game); } return 0; }
步骤2:注册事件监听时传递this作为用户数据
修改SetupSDL中的SDL_AddEventWatch调用,把this(当前Game实例)作为第二个参数传入:
bool Game::SetupSDL() { // ... 其他初始化代码 ... SDL_AddEventWatch(Game::OnResize, this); // 传递Game实例指针作为用户数据 return true; }
注意事项
- 不要直接强制转换非静态成员函数为
SDL_EventFilter,这会导致运行时内存错误或逻辑异常,因为this指针无法被正确传递。 - 如果你的逻辑需要用到窗口指针,可以通过
Game类的window成员变量访问,无需在用户数据中单独传递。
内容的提问来源于stack exchange,提问作者K. Russell Smith
相关产品推荐
相关产品推荐

