【问题标题】:Passing in C++ Method as a Function Pointer?将 C++ 方法作为函数指针传递?
【发布时间】:2017-11-26 10:26:27
【问题描述】:

我创建了一个名为 InputControl 的类。我正在使用一个名为 GLFW 的库和一个函数 glfwSetKeyCallback。函数定义为:

GLFWkeyfun glfwSetKeyCallback(GLFWwindow * 窗口,GLFWkeyfun cbfun)

Typedef如下:

typedef void(* GLFWkeyfun) (GLFWwindow *, int, int, int, int)

问题是我无法将我的方法转换为函数指针。我觉得我已经尝试以各种可能的方式投射它。我不确定我还需要如何转换此方法。是否有特定于将相对方法作为函数指针传递的东西? 我的代码如下:

#pragma once
#include <GLFW/glfw3.h>
#include "config.h"

class InputControl {
public:
    void bind();
    void unbind();

private:
     void __glfw__keycallback_bind(GLFWwindow* window, int key, int scancode, int action, int mods);
};

输入控制.cpp

void InputControl::bind() {
    glfwSetKeyCallback(__application__window, __glfw__keycallback_bind);
}

void InputControl::unbind() {

}

void InputControl::__glfw__keycallback_bind(GLFWwindow * window, int key, int scancode, int action, int mods) {
//... other code here
}

Visual Studio 给我以下错误

“void (InputControl::*)(GLFWwindow *window, int key, int scancode, int action, int mods)”类型的 E0167 参数与“GLFWkeyfun”类型的参数不兼容

【问题讨论】:

  • 无法将非静态类方法指针转换为常规函数指针。这些是完全不同且不相容的实体。停止尝试这样做。不幸的是,您的问题没有提供足够的上下文来提供替代解决方案。实际的 InputControl 对象将驻留在哪里?
  • 与您的问题无关,但不要使用两个前导下划线定义名称或符号。这些是为所有范围内的编译器和标准库保留的。请参阅this old question and its answers 了解更多信息。
  • 扩展@AnT 的评论。方法作用于类的实例。常规函数无法确定要作用于哪个实例。

标签: c++ pointers glfw


【解决方案1】:

一个非静态成员函数需要一个对象来处理。您需要一个非成员函数或静态成员函数作为回调。如果您绝对需要在回调中访问 InputControl 类的实例,您可以使用 glfwSetWindowUserPointer() 设置窗口的用户指针,然后回调可以使用该指针调用非静态成员函数:

class InputControl {
public:
    void bind();
    void unbind();

private:
     static void keyCallbackStatic(GLFWwindow* window,
                                   int key,
                                   int scancode,
                                   int action,
                                   int mods);
     void keyCallback(GLFWwindow* window,
                      int key,
                      int scancode,
                      int action,
                      int mods);
};

void InputControl::bind() {
    glfwSetWindowUserPointer(applicationWindow, this);
    glfwSetKeyCallback(applicationWindow, keyCallbackStatic);
}

void InputControl::keyCallbackStatic(GLFWwindow* window,
                                     int key,
                                     int scancode,
                                     int action,
                                     int mods)
{
    InputControl* that = static_cast<InputControl*>(glfwGetWindowUserPointer(window));
    that->keyCallback(window, key, scancode, action, mods);
}

void InputControl::keyCallback(GLFWwindow* window,
                               int key,
                               int scancode,
                               int action,
                               int mods)
{
    // Do whatever
}

由您来确保您的 InputControl 对象与您的窗口一样长时间保持活动状态,并且除了 InputControl 对象指针之外,没有其他任何东西可以将窗口的用户指针设置为任何东西。

【讨论】:

  • 你打败了我。我正要发布相同的答案;-)
【解决方案2】:

你可以有一个调用你的成员函数的接口:

class App {
public:
    void onKeyDown(int key, int action) {
        if (action == 1)
            std::cout << "Pressed: " << static_cast<char>(key) << '\n';
        if (action == 0)
            std::cout << "Released: " << static_cast<char>(key) << '\n';
    }
};

class Interface {
public:
    static void* p;

    static void OnKeyDown(GLFWwindow * window, int key, int scancode, int action, int mods) {
        ((App*)(p))->onKeyDown(key, action);
    }
};
void * Interface::p;

int main()
{
    App app;

    [...]

    glfwSetKeyCallback(window, Interface::OnKeyDown);

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-22
    • 2021-10-05
    • 2013-02-15
    • 2022-08-14
    • 1970-01-01
    • 2017-10-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多