将成员函数传递给 glfwSet*Callback

Pass Member Function To glfwSet*Callback

我正在尝试设置一个 'event receiver' class 以将 GLFW 回调包装到一个 class 用户可以继承但在传递 base-class 成员函数到 GLFW 'set callback' 函数中。

#include <GLFW/glfw3.h>

//
//
//  Event Receiver Framework

enum EventTypes {
    Keyboard = 1,
    Mouse = 2
};

struct Event {
    EventTypes Action;
    //  Other Event Related Values
};

class EventReceiver {
    void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
        Event NewEvent;
        NewEvent.Action = EventTypes::Keyboard;
        OnEvent(NewEvent);
    }

public:
    virtual void OnEvent(Event& NewEvent) = 0;
};

//
//
//  Application Framework

class MyApplication {
    GLFWwindow* window;
public:
    void SetEventReceiver(EventReceiver* EventHandler) {
        glfwSetKeyCallback(window, &EventHandler->key_callback);
    }

};

//
//  
//  User-Defined Event Receiver

class MyEventReceiver : public EventReceiver {
public:
    void OnEvent(Event& NewEvent) {
        if (NewEvent.Action == EventTypes::Keyboard) {
            //  Custom Event Actions
        }
        else if (NewEvent.Action == EventTypes::Mouse) {
            //  Custom Event Actions
        }
    }
};

//
//
//  Main

int main() {
    MyEventReceiver _Events;
    MyApplication _App;
    _App.SetEventReceiver(&_Events);
    //
    //  Do logic
    //
    return 0;
}

这实质上提供了一个基础-class 具有纯虚函数供用户继承和覆盖以提供他们自己的事件发生时的逻辑。用户定义的子 class 旨在传递到更大的 'application-framework' class 中,后者进行必要的调用以设置 GLFW 回调函数。

当然你不能将成员函数作为函数参数传递给期望 c 风格函数的函数,因为你必须提供对 class 实例的访问,换句话说,你必须提供 class 实例,因此被调用的成员函数知道使用什么对象作为 'this pointer'.

对于 GLFW 中的 'glfwSet*Callback' 函数,我不确定如何做到这一点。

在 GLFW 中只能像这样使用静态成员函数,相反,如果需要,您可以在这些情况下使用 glfwGetWindowUserPointer 和 glfwSetWindowUserPointer 来提供对底层 class 对象的访问。

#include <GLFW/glfw3.h>

//
//
//  Event Receiver Framework

enum EventTypes {
    Keyboard = 1,
    Mouse = 2
};

struct Event {
    EventTypes Action;
    //  Other Event Related Values
};


class EventReceiver {
    static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
        Event NewEvent;
        NewEvent.Action = EventTypes::Keyboard;
        static_cast<EventReceiver*>(glfwGetWindowUserPointer(window))->OnEvent(NewEvent);
    }

public:
    virtual void OnEvent(Event& NewEvent) = 0;
    friend class MyApplication;
};

//
//
//  Application Framework

class MyApplication {
    GLFWwindow* window;
public:
    void SetEventReceiver(EventReceiver* EventHandler) {
        glfwSetWindowUserPointer(window, EventHandler);
        glfwSetKeyCallback(window, &EventReceiver::key_callback);
    }

};

//
//  
//  User-Defined Event Receiver

class MyEventReceiver : public EventReceiver {
public:
    void OnEvent(Event& NewEvent) {
        if (NewEvent.Action == EventTypes::Keyboard) {
            //  Custom Event Actions
        }
        else if (NewEvent.Action == EventTypes::Mouse) {
            //  Custom Event Actions
        }
    }
};

//
//
//  Main

int main() {
    MyEventReceiver _Events;
    MyApplication _App;
    _App.SetEventReceiver(&_Events);
    //
    //  Do logic
    //
    return 0;
}