我正计划为我的Window类设计。目标是提供一个抽象,用于创建一个准备用于OpenGL渲染的平台无关窗口。我正在考虑让一个类'Window'成为公共接口,并且'WindowImpl'类处理这项工作。将Window作为WindowImpl的朋友并在Window中调用WindowImpl函数会导致问题吗?从技术上讲,WindowImpl不会被实例化正确吗?因此不会调用析构函数,这意味着不会调用Window析构函数,因此需要使用destroy函数。实施例
class MyWindow
{
public:
void create(width, height, title)
{
WindowImpl::create(width, height, title);
open = true;
}
void close()
{
WindowImpl::destroy();
open = false;
}
bool isOpen()
{
return open;
}
private:
bool open;
};
class WindowImpl
{
friend class MyWindow;
private:
static void create(width, height, title) {} // Creates the window
static void destroy()
{
XCloseDisplay(display);
}
static Display* display;
static Window window;
static GLXContext context;
};
我不知道我是否会以正确的方式行事,或者如果我让事情变得更加复杂,那么他们就需要这样做。由于将根据目标平台编译不同的WindowImpl,我希望尽可能多地远离用户,保留Window类中窗口标题和分辨率等所有数据,并且必要的任何更改都可以没有WindowImpl跟踪任何更多的实现特定的东西。
答案 0 :(得分:0)
如果真的必须与平台无关,那么我的建议是使用这样的东西:
class WindowImpl
{
public:
virtual void setOwner(Window* pOwner) = 0
virtual void create(width, height, title) = 0;
virtual void close() = 0;
};
class Window
{
public:
void create(width, height, title)
{
mImpl->create(width, height, title);
open = true;
}
void close()
{
open = false;
mImpl->destroy();
}
Window(std::unique_ptr<WindowImpl> pImpl)
: mImpl(pImpl)
{
}
private:
std::unique_ptr<WindowImpl> mImpl;
};
// Then off somewhere else...
class WindowImplX11 : public WindowImpl
{
public:
void setOwner(Window* pOwner) {
mOwner = pOwner;
}
void destroy() {
XCloseDisplay(display);
}
private:
// Pointer back to the owner just in case (e.g. event
// delivery); if weak_ptr worked with unique_ptr, that
// would be better.
Window* mOwner;
Display* display;
GLXContext context;
};
这是Bridge模式的简易版本,当您有两个需要链接在一起的不兼容对象层次结构时,通常会使用它。这是一个退化的情况(因为“层次结构”中只有一个类),但它仍然是一个有用的思考技巧。可能最着名的例子是Java AWT(但是AWT称之为“Peer”而不是“Impl”)。
当然,你在前端和后端之间分配职责的确切方式是你需要自己决定的事情,而且可能会有一些来回。例如,您可以确定OpenGL上下文是一个非常重要的概念,您需要将其公开给客户端。对于像标准方式尚未完全支持的vsync fences这样的事情也是如此。是的,我在看着你,OS X。
唯一的问题是你如何构建一个Window及其Impl。传统的方法是使用抽象工厂:
class Toolkit
{
public:
std::unique_ptr<Window> createWindow() = 0;
};
// then elsewhere...
// Should have been in the library, only left out by oversight.
template<typename T, typename ...Args>
std::unique_ptr<T> make_unique( Args&& ...args )
{
return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) );
}
class ToolkitX11 : public Toolkit
{
public:
std::unique_ptr<Window>
createWindow() {
return make_unique<Window>(make_unique<WindowImplX11>());
}
};
还有其他方式更现代化。