目前,在我正在开发的游戏中,我有一个窗口类:
class UserWindow{
*interface here*
};
我已经竭尽全力避免暴露这个窗口的实现细节;具体来说,它在底层使用了 GLFW。我不想向客户端公开任何 GLFW,在我最终最终删除/替换它的情况下。一切都很好,直到我终于开始处理窗口的键输入。你看,GLFW 使用宏来识别键,如下所示:
auto GLFWKeyPressCallback(GLFWwindow* wind, int key, int, int, int) -> void {
if(key == GLFW_KEY_???)
*do stuff*
}
大多数 C++ 程序员都知道,宏是有毒的,应该避免使用。这里的问题是我为用户提供了一个 UserWindowEventListener 接口(interface)来连接和接收事件。问题是,如何在不公开整个 GLFW API 本身的情况下公开这些 GLFW key 的标识符?由于 GLFW 使用前面提到的(邪恶的)宏来识别这些,它们会渗入全局命名空间,这破坏了拥有“内部”命名空间的想法。我想到的唯一其他解决方案是使用一个普通的 ol' 结构,其中包含每个键的静态整数,并将它们分配到 .cpp 文件中,如下所示:
.hpp:
struct UserWindowKey{
static const int up, down, left, right... (repeat ad nauseam)
};
.cpp:
const int UserWindowKey::up = GLFW_KEY_UP...
然而,这看起来很乏味、难以管理,而且通常感觉完全是一种糟糕的做法。有什么想法吗?
编辑:伪代码中的一些实现细节,以消除任何歧义:
用户窗口:
//constructor
UserWindow(){
//key_func just fires the signal that's in the event handler below.
glfwSetKeyCallback(window_handle, key_func);
}
用户窗口事件监听器:
struct UserWindowEventListener{
key_signal_type key_signal;
};
用法:
auto main() -> int {
UserWindow wind;
wind.event_listener.key_signal.connect(*MY_FUNC*);
wind.event_listener.poll();
}
最佳答案
我会创建一个中间方法,将 GLFW key 转换为您自己的 key ,以您熟悉且感觉理智的方式定义。就个人而言,我会使用这样的枚举:
enum MyKeys
{
UP,
DOWN,
LEFT,
RIGHT,
// the rest
}
然后用户会为您提供回调,而您会为 GLFW 提供不同的回调。当 GLFW 调用您的回调时,您将 key 转换为您的公共(public)枚举,然后触发用户提供的回调。
回调的伪代码可能类似于:
auto GLFWKeyPressCallback(GLFWwindow* wind, int glfwKey, int a, int b, int c) -> void
{
auto myKey = ConvertGlfwKeyToMyKey(glfwKey);
user_callback(myKey, a, b, c);
}
user_callback 签名看起来像这样:
void user_callback(MyKeys, int, int, int);
ConvertGlfwKeyToMyKey 可能看起来像这样:
MyKeys ConvertGlfwKeyToMyKey(glfwKey)
{
switch (glfwKey)
{
case GLFW_KEY_UP:
return MyKeys.UP;
case GLFW_KEY_DOWN:
return MyKeys.DOWN;
// the rest
}
}
该系统的明显缺点是您必须通过并填写 Convert 功能。优点是您已经从用户那里抽象出所有 GLFW 内容,而无需使用任何宏或用一堆结构污染您的代码。
或者,您可以选择其他一些机制将 GLFW key 映射到 MyKeys。如果 GLFW 键覆盖了一个范围内的所有值,您可以按照相同的顺序对您的枚举进行排序,然后只需将 GLFW int 偏移并类型转换为您的枚举。
关于c++ - 接口(interface)和实现问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24567061/