0

我在这样的标题中定义了一个类(缩写):

class CairoRenderer
{
public:
    CairoRenderer();
    ~CairoRenderer();
...
protected:
    cairo_t* m_context;
    cairo_surface_t* m_surface;
};

cairo_t 和 cairo_surface_t 是由Cairo图形库定义的类型。

我遇到的问题是,如果我想使用这个类或其来自另一个库或应用程序的派生类,我还需要包含 cairo 标头,因为我通过 CairoRenderer 标头“泄漏”了 cairo 类型。我希望同一个库中的此类(或其任何子类)可以在外部使用,而无需包含 cairo 标头或链接到 cairo 库。

所以接下来我尝试的是按照Wikipedia示例使用 pimpl 技术,因为它看起来可以完成我想要实现的目标:

CairoRenderer.h(缩写)

class CairoRenderer
{
...
protected:
    struct CairoRendererImpl;
    CairoRendererImpl* m_pimpl;
};

CairoRenderer.cpp(缩写)

#include "CairoRenderer.h"
#include "cairo.h"

....

struct CairoRenderer::CairoRendererImpl 
{
public:
    CairoRendererImpl() : m_surface(NULL), m_context(NULL) { }
    ~CairoRendererImpl() 
    {
        cairo_surface_destroy(m_surface);
        cairo_destroy(m_context);
    }

    void Initialize(cairo_t* context, cairo_surface_t* surface)
    {
        m_context = context;
        m_surface = surface;
    }

    cairo_surface_t* surface() { return m_surface; }
    cairo_t* context() { return m_context; }

private:
    cairo_surface_t* m_surface;
    cairo_t* m_context;
};

CairoRenderer::CairoRenderer() : m_pimpl(new CairoRendererImpl()) { ... }

CairoRenderer::~CairoRenderer() { delete m_pimpl; }

我遇到的问题是,当我尝试从派生类访问 m_pimpl 成员时,出现编译器错误:

error C2027: use of undefined type 'CairoRenderer::CairoRendererImpl'

我做错了吗?还是我想做的甚至可能?

4

3 回答 3

4

您正确使用了 pimpl 成语,这就是您的问题。您已经隐藏了所有外部代码的定义CairoRendererImpl包括派生中的代码。

首先,我想质疑拥有具有数据成员和非虚拟析构函数的基类的价值。您应该查看要子类化的根本原因CairoRenderer,并考虑替代解决方案。

如果您确实想支持子类化,但仅支持库中的类,那么您应该将定义CairoRendererImpl放入一个共享头文件中,该文件可以包含在CairoRendererheirachy 中所有相关类的实现文件中。

于 2011-10-13T12:50:58.650 回答
1

pimpl 成语使用没问题。

避免必须包含 cairo.h 文件的方法是在您的 CairoRenderer.h 文件中包含声明(即前向声明

class CairoRendererImpl;

就这样吧;不要包括 CairoRendererImpl.h,因为需要拖入 cairo.h 的定义。

您可以这样做,因为 CairoRenderer 只需要一个指向实现的指针 - 只要您实际上不调用头文件中的任何方法(例如内联函数),编译器就不需要查看 CairoRendererImpl 类的完整声明。

在 CairoRenderer.cc 中,您可以包含 CairoRendererImpl.h 文件(它将获得 cairo.h 的内容,但此时这是您真正想要/需要的)。

h, h

于 2011-10-13T13:12:43.283 回答
0

我认为struct CairoRenderer::CairoRendererImpl是错误的。由于您不使用名称空间,因此像这样的简单定义就足够了:

struct CairoRendererImpl 
{
    ...
}

您还必须稍微调整一下您的CairoRenderer课程:

struct CairoRendererImpl;

class CairoRenderer
{
...
protected:
    CairoRendererImpl* m_pimpl;
};
于 2011-10-13T12:47:16.533 回答