I have a class defined in a header like so (abbreviated):
class CairoRenderer
{
public:
CairoRenderer();
~CairoRenderer();
...
protected:
cairo_t* m_context;
cairo_surface_t* m_surface;
};
cairo_t and cairo_surface_t are types defined by the Cairo graphics library.
The problem I have is that if I want to use this class or its derived classes from another library or application, I need to include the cairo headers as well because I am "leaking" the cairo types out through the CairoRenderer header. I want this class (or any subclass of it) in the same library to be usable externally without needing to include the cairo header or link against the cairo libraries.
So the next thing I tried was to use the pimpl technique as per the Wikipedia example because it looked like it could do what I wanted to achieve:
CairoRenderer.h (abbreviated)
class CairoRenderer
{
...
protected:
struct CairoRendererImpl;
CairoRendererImpl* m_pimpl;
};
CairoRenderer.cpp (abbreviated)
#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; }
The problem I have is when I try to access the m_pimpl member from a derived class, I get the compiler error:
error C2027: use of undefined type 'CairoRenderer::CairoRendererImpl'
Am I doing pimpl wrong? Or is what I want to do even possible?
You are using the pimpl idiom correctly, and that is your problem. You have hidden the definition of CairoRendererImpl
from all external code, including the code in derived classes.
First of all I would like to call into question the value of having a base class that has data members and a non-virtual destructor. You should look at the underlying reasons that you want to subclass CairoRenderer
, and consider alternative solutions.
If you do want to support subclassing, but only for the classes within your library, then you should put the definition of CairoRendererImpl
into a shared header file that can be included by the implementation files of all of the relevant classes in the CairoRenderer
heirachy.