我想设计一个窗口对象,它的任务是处理GLFW窗口的所有功能(初始化,回调,输入处理...)
其中最重要的事情是渲染循环。最天真的设计,我能想到的是有renderloop法取一个函数指针没有参数,然后调用它的循环方法中,如下所示:
class Window
{
public:
Window();
~Window();
void WindowLoop(void (*f) (void));
protected:
GLFWwindow* window;
};
void Window::WindowLoop(void (*f) (void))
{
while(!glfwWindowShouldClose(window))
{
f();
glfwPollEvents();
}
}
然而,这施加了很大的局限性。首先,它意味着该函数不能带任何参数。这可能会或可能不会是一个问题。
我做了一些研究,显然可以传递函数指针是利用参数的任意数目,但是这似乎是既困难又防止建议。
另一种选择是一般的函子,然后这些参数可以被定义为类/结构的一部分,避免了必须处理的。
有可能是我不知道的,以及其他潜在的设计。
这将是C ++的渲染循环良好的设计,试图使用和第二,执行速度的第一优先考虑通用性?
我简短的回答将是:
使用原始函数指针的std::function
代替。这给你,因为它可以容纳更多的灵活性:
你仍然被限制在定义呼叫签名,但你可以给这可能是所有你需要你的回调上下文。
所以,这是怎么会看:
#include <functional>
class Window
{
public:
Window();
~Window();
void WindowLoop(std::function<void()> f);
protected:
GLFWwindow* window;
};
void Window::WindowLoop(std::function<void()> f)
{
while(!glfwWindowShouldClose(window))
{
f();
glfwPollEvents();
}
}
(它看起来比OP的原始样本没有太大的不同。)
三思而后行,我发现它值得一提的小工具集,他们提供什么样的解决方案(如有同样的问题来解决)。
这两个通用的解决方案
virtual
方法可以覆盖。信号基本上是没有别的比函数指针(或std::function
或东西可比)的容器。该信号被发射(即,所存储的函数指针称为)在某些情况下。因此,其他对象可以得到该情况(在信号注册他们的信号处理)通知。因此,一个信号是不同的函数指针(多个)不暂时提供,但存储在成员变量实际上类似像上面。
另一种方法是调用一个方法virtual
在某些情况下。要添加自定义行为时,RESP。基类必须被导出并在追求的virtual
方法必须被重写。
在OP的情况下,这可能是这样的:
class Window
{
public:
Window();
~Window();
void WindowLoop();
protected:
virtual void step();
protected:
GLFWwindow* window;
};
void Window::WindowLoop()
{
while(!glfwWindowShouldClose(window))
{
step();
glfwPollEvents();
}
}
void Window::step() { /* empty placeholder */ }
要使用在应用程序中,派生类Window
的是强制性的:
class GameWindow: public Window {
protected:
virtual void step() override;
};
void GameWindow::step()
{
// Do the game step stuff (e.g. rendering)
// where this (of type GameWindow) can provide the necessary context.
}
关于Qt,存在用于对例如各种情况和virtual
方法的信号事件处理程序中的小部件。有大多的非此即彼/或选择 - 我不记得这两个可用的东西。例如。可以存在用于QPushButton::clicked()
注册的信号处理程序,但以自定义的事件处理程序作为mousePressEvent()
,一个Qt插件必须被重载以覆盖事件处理方法。 (也有事件过滤器的概念,但恕我直言,这是不完全一样的。)
gtkmm而不是(至少在2.0版本我在过去使用)提供的一切我还记得virtual
方法和信号。所以,总有要么得到一个gtkmm的小部件或更改的选择,只是通过注册的信号处理/延长的gtkmm控件的行为。这可能会引入一些额外的性能开销,但它是应用程序非常方便。