首页 > 解决方案 > C++ 中不带括号的方法

问题描述

所以我目前正在编写一个 C++ OpenGL 程序,而且我对这门语言还很陌生。什么是没有括号的方法?

我的代码块:

程序.cpp:

Input input;

glfwSetKeyCallback(window, input.HandleInput); //On this line input.HandleInput is the question at hand

输入.h

class Input
{
public:
    void HandleInput(GLFWwindow* window, int key, int scancode, int action, int mods);
private:
};

输入.cpp

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include <iostream>

#include "Input.h"

void Input::HandleInput(GLFWwindow* window, int key, int scancode, int action, int mods)
{

     if (key == GLFW_KEY_F && action == GLFW_PRESS)
     {
         std::cout << key << " pressed.";
     }

}

如果有人能告诉我如何正确执行 input.HandleInput 方法,我将不胜感激。

标签: c++methodsglfw

解决方案


该方法glfwSetKeyCallback将函数指针作为其参数。函数指针是 C 和 C++ 功能中相对重要的部分,并且是实现回调的常用习惯,如本例所示。

GLFW 对传递给它的函数的作用是它具有系统事件的内部轮询功能(您可以使用 调用glfwPollEvents();),在遇到系统事件时,会将其转换为可以使用回调解释的与系统无关的形式你提供的。

但是,GLFW 是用 C 编写的,无法处理 C++ 原生的更复杂、更高级的函数指针或仿函数,因此当我们将函数指针传递给 GLFW 时,我们需要将其简化为更简单的形式。对象的成员函数不会剪切它。这是因为这样的方法:

class Input
{
public:
    void HandleInput(GLFWwindow* window, int key, int scancode, int action, int mods);
private:
};

偷偷地,根据编译器,实际上是这样的:

void Input__HandleInput(Input * ptr, GLFWwindow* window, int key, int scancode, int action, int mods);

由于此签名与 GLFW 对回调的期望不匹配,因此它不会接受它。

如果您打算使用类函数作为此函数的回调,则需要将其设为静态。

struct Input {//'class' is fine, but 'struct' reduces boilerplate
    static void HandleInput(GLFWwindow* window, int key, int scancode, int action, int mods);
};

int main() {
    glfwInit();
    GLFWWindow* window = glfwCreateWindow(/*...*/);
    glfwSetKeyCallback(window, Input::HandleInput);
}

但是,这可能会给您带来问题。毕竟,您可能专门为此回调功能编写了一个类,以提供对您需要的行为的一些封装。被迫恢复使用静态函数或全局函数会破坏此目的。

相反,您需要使用 GLFW 集成的用户指针功能。

struct InputHandler {
    static void HandleKey(GLFWwindow* window, int key, int scancode, int action, int mods) {
        //Perfectly legal: we fully intend to only permit the User Pointer to be of type 'InputHandler*'
        InputHandler & handler = *reinterpret_cast<InputHandler*>(glfwGetWindowUserPointer(window));
        handler.handleKeyImpl(window, key, scancode, action, mods);
    }
    void handleKeyImpl(GLFWwindow* window, int key, int scancode, int action, int mods) {
        /*...*/
    }
};

int main() {
    glfwInit();
    InputHandler input;
    GLFWWindow* window = glfwCreateWindow(/*...*/);
    glfwSetWindowUserPointer(window, &input);
    glfwSetKeyCallback(window, Input::HandleInput);
}

推荐阅读