给静态函数访问数据而不将数据作为参数传递

时间:2014-12-22 05:07:57

标签: c++ callback global-variables static-methods glfw

我在我的C ++应用程序中使用GLFW作为窗口,我正在尝试使用GLFW的回调来获取输入事件。例如,这是您获取关键事件的方式:

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods){
    // Do something with event data.
}

int main(){
    // initialize window (I have no problems with this step)

    glfwSetKeyCallback(window, key_callback);
    // Now when a key is pressed in the window it will call this function.
}

问题:

在我的key_callback中,我想使用在key_callback函数之外声明的变量,因为我无法更改key_callback的参数,所以我无法传递对变量的引用。

现在,在上面的给定示例中,我可以简单地在int main()之外声明我的变量,key_callbackint main()都可以访问变量的同一个实例。

我想要的使用:

我希望有一个WindowWrapper类来创建和管理glfwWindow的生命周期,这包括设置事件回调。

WindowWrapper.h

// Includes
class WindowWrapper{
private:
    Centrum* g_centrum_;
    GLFWwindow* window_;
    std::thread thread_;
public:
    WindowWrapper();
    WindowWrapper(Centrum* g_centrum);
    ~WindowWrapper();
private:
    // Callbacks
    static void key_callback(
        GLFWwindow* window, int key, int scancode, int action, int mods
        );
};

WindowWrapper.cpp

WindowWrapper::WindowWrapper(Centrum* g_centrum){
    g_centrum_ = g_centrum;
    // Initialize window

    glfwSetKeyCallback(window_, key_callback); // Problems

    // Window loop and OpenGL stuff
}
WindowWrapper::~WindowWrapper(){
    thread_.join(); // Don't worry about this, it works but, I will make it safer.
    glfwDestroyWindow(window_);
    printf("WindowWrapper Completely Destructed!\n"); // For testing purposes
}

void WindowWrapper::key_callback(
    GLFWwindow* window, int key, int scancode, int action, int mods
    ){
    // This function is declared static in the class declaration.
    // And as a result I cannot use g_centrum_ since it is a non-static variable
    // Essentially I want to be able to access g_centrum_ from this function
    g_centrum_->input_eventmanager_->key_eventmanager_->
        TriggerKeyEvent(key, action, mods);
}

我认为这样做的第一种方法是传递对g_centrum的引用,但GLFW并不会对回调参数产生任何偏差。

我的第二次尝试是在构造函数中声明和定义回调,但你不能这样做。

我的第三次尝试是让g_centrum_静态,但我必须在构造函数之外给它引用,我不认为这是一个优雅的解决方案。

2 个答案:

答案 0 :(得分:7)

在注册回调之前,使用glfwSetWindowUserPointer()将包装器指针关联到窗口。调用回调后,您可以使用glfwGetWindowUserPointer()来检索它。这些API在GLFW documentation

中描述
  

窗口用户指针

     

每个窗口都有一个用户指针,可以使用 glfwSetWindowUserPointer 进行设置,并使用 glfwGetWindowUserPointer 获取。这可以用于您需要的任何目的,并且在窗口的整个生命周期内不会被GLFW修改。

例如,您可以在WindowWrapper构造函数中执行此操作:

WindowWrapper::WindowWrapper(Centrum* g_centrum){
    g_centrum_ = g_centrum;
    // Initialize window first
    ...
    // Now, associate the wrapper to the window
    glfwSetWindowUserPointer(window_, this);

    glfwSetKeyCallback(window_, key_callback); // Problems

    // Window loop and OpenGL stuff
}

然后,在你的回调中:

void WindowWrapper::key_callback(
    GLFWwindow* window, int key, int scancode, int action, int mods
    ){

    void *data = glfwGetWindowUserPointer(window);  
    WindowWrapper *w = static_cast<WindowWrapper *>(data);

    w->g_centrum_->input_eventmanager_->key_eventmanager_->
        TriggerKeyEvent(key, action, mods);
}

答案 1 :(得分:1)

您可以使用静态地图将每个GLFWindow*映射到相应的WindowWrapper

private:
    static std::map<GLFWindow*, WindowWrapper*> m_instanceMap;
    ...

然后在构造函数中,向此映射添加一个条目:

m_instanceMap.insert(std::make_pair(window_, this));

在析构函数中,将其删除:

m_instanceMap.erase(window_);

现在,在(静态)回调方法中,您可以查找类实例,并调用每个实例方法:

void WindowWrapper::key_callback(
    GLFWwindow* window, int key, int scancode, int action, int mods)
{
    WindowWrapper* pThis = m_instanceMap[window];
    pThis->keyHandler(key, scancode, action, mods);
}

keyHandler()是常规实例方法。