设计一个Window类(Designing a Window class)

编程入门 行业动态 更新时间:2024-10-23 18:26:39
设计一个Window类(Designing a Window class)

我正计划为我的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跟踪任何更多的实现特定的东西。

I'm planning out a design for my Window class. The goal is to provide an abstraction for creating a platform agnostic window ready for OpenGL rendering. I'm thinking of having a class 'Window' be the public interface, and a 'WindowImpl' class handle the work. Would making Window a friend of WindowImpl and calling WindowImpl functions inside Window cause issues? Technically, WindowImpl wouldn't be instantiated correct? So the destructor wouldn't be called which means the Window destructor wouldn't be called so a destroy function would be needed. Ex.

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; };

I don't know if I'm going in the right way with this, or if I'm making things more complicated then they need to be. Since a different WindowImpl will be compiled depending on the target platform, I want to keep as much of it away from the user as possible, keeping all data like the window title and resolution inside of the Window class and any changes that are necessary can be made without the WindowImpl keeping track of anything more then the implementation specific stuff.

最满意答案

如果它真的必须与平台无关,那么我的建议是使用这样的东西:

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>()); } };

还有其他一些更现代的方式。

If it really has to be platform-agnostic, then my suggestion is to use something like this:

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; };

This is a light version of the Bridge pattern, which is commonly used when you have two incompatible object hierarchies which you need to link together. This is a degenerate case (since the "hierarchy" has only one class in it), but it's still a useful technique to think about. Probably the most famous example of this is Java AWT (however AWT calls it "Peer" rather than "Impl").

Exactly how you split the responsibilities between the front end and back end is, of course, something that you need to decide for yourself, and there will probably be some back-and-forth. You may, for example, decide that an OpenGL context is a sufficiently important concept that you need to expose it to clients. The same goes for things like vsync fences which aren't fully supported in the standard way yet. Yes, I'm looking at you, OS X.

The only catch is how you construct a Window and its Impl. The traditional way is to use an abstract factory:

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>()); } };

There are other ways which are a little more Modern.

更多推荐

本文发布于:2023-04-29 12:06:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1336302.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:Window   Designing   class

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!