Избегайте утечки внешних типов в классе C ++ - PullRequest
0 голосов
/ 13 октября 2011

У меня есть класс, определенный в заголовке следующим образом (сокращенно):

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

cairo_t и cairo_surface_t - это типы, определенные в графической библиотеке Cairo .

У меня проблема в том, что если я хочу использовать этот класс или его производные классы из другой библиотеки или приложения, мне нужно также включить заголовки cairo, потому что я «пропускаю» типы cairo через заголовок CairoRenderer.Я хочу, чтобы этот класс (или любой его подкласс) в той же библиотеке можно было использовать извне, без необходимости включать заголовок cairo или ссылку на библиотеки cairo.

Поэтому следующее, что я попробовал, - это использование pimpl.техника в соответствии с примером Wikipedia , потому что это выглядело так, как будто оно могло делать то, что я хотел достичь:

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'

Я неправильно делаю pimpl?Или то, что я хочу сделать, даже возможно?

Ответы [ 3 ]

4 голосов
/ 13 октября 2011

Вы правильно используете иероглиф pimpl, и это ваша проблема.Вы скрыли определение CairoRendererImpl из всего внешнего кода, , включая код в производных классах.значение наличия базового класса, который имеет члены данных и не виртуальный деструктор.Вам следует рассмотреть основные причины, по которым вы хотите создать подкласс CairoRenderer, и рассмотреть альтернативные решения.

Если вы do хотите поддерживать подклассы, но только для классов в вашей библиотеке,затем вы должны поместить определение CairoRendererImpl в файл общего заголовка, который может быть включен в файлы реализации всех соответствующих классов в иерархии CairoRenderer.

1 голос
/ 13 октября 2011

идиома pimpl используется нормально.

Чтобы избежать включения файла (ов) cairo.h, в вашем файле CairoRenderer.h необходимо иметь инструкцию (например, предварительное объявление )

class CairoRendererImpl;

и оставь это на этом; делать , а не включать CairoRendererImpl.h, поскольку это НУЖНО перетащить в определения cairo.h.

Вы можете сделать это, потому что CairoRenderer нужен только указатель на реализацию - при условии, что вы на самом деле не вызываете какие-либо методы из заголовочного файла (например, встроенные функции), компилятору не нужно видеть полное объявление класса CairoRendererImpl.

В CairoRenderer.cc вы можете включить файл CairoRendererImpl.h (который получит материал cairo.h, но на данный момент это именно то, что вам действительно нужно / нужно).

НТН, ч

0 голосов
/ 13 октября 2011

Я думаю struct CairoRenderer::CairoRendererImpl неправильно.Поскольку вы не используете пространства имен, достаточно простого определения, подобного этому:

struct CairoRendererImpl 
{
    ...
}

Также вам нужно немного настроить свой класс CairoRenderer:

struct CairoRendererImpl;

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