设计一个Window类

时间:2014-02-04 01:25:31

标签: c++ class-design

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

1 个答案:

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

还有其他方式更现代化。

相关问题