避免泄漏 C++ 中的外部类型班级
我在标头中定义了一个类,如下所示(缩写):
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'
我做的pimpl错了吗?或者我想做的事情是否可能?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您正确使用了 pimpl 习惯用法,这就是您的问题。您已对所有外部代码(包括派生类中的代码)隐藏了
CairoRendererImpl
的定义。首先,我想质疑具有数据成员和非虚拟析构函数的基类的价值。您应该查看想要子类化
CairoRenderer
的根本原因,并考虑替代解决方案。如果您确实想要支持子类化,但仅限于库中的类,那么您应该将
CairoRendererImpl
的定义放入一个共享头文件中,该文件可以由CairoRenderer
heirachy 中所有相关类的实现文件。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 theCairoRenderer
heirachy.pimpl 惯用语用得还可以。
避免必须包含 cairo.h 文件的方法是在 CairoRenderer.h 文件中包含以下声明(即 前向声明)
,然后就这样;不要包含 CairoRendererImpl.h,因为这需要拖入 cairo.h 的定义。
您可以这样做,因为 CairoRenderer 只需要一个指向实现的指针 - 只要您实际上不调用头文件中的任何方法(例如内联函数),编译器就不需要查看完整的声明CairoRendererImpl 类的。
在 CairoRenderer.cc 中,您可以包含 CairoRendererImpl.h 文件(它将获取 cairo.h 内容,但此时这正是您真正想要/需要的)。
哈,
小时
The pimpl idiom used ok.
The way to avoid having to include the cairo.h file(s) is to have, in your CairoRenderer.h file the statement (ie a forward declaration)
and leave it at that; do not include CairoRendererImpl.h since that will NEED to drag in definitions of cairo.h.
You can do this because CairoRenderer only needs a pointer to an implementation - as long as you do not actually call any methods from the headerfile (e.g. inline functions) the compiler doesn't need to see the full declaration of the CairoRendererImpl class.
In the CairoRenderer.cc you can include the CairoRendererImpl.h file (which will get the cairo.h stuff but at this point that is what you actually want/need).
hth,
h
我认为 struct CairoRenderer::CairoRendererImpl 是错误的。由于您不使用名称空间,因此像这样的简单定义就足够了:
此外,您还必须稍微调整您的
CairoRenderer
类:I think
struct CairoRenderer::CairoRendererImpl
is wrong. Since you do not use namespaces, a simple definition like this would suffice:Also you have to adjust your
CairoRenderer
class a bit: