PIMPL Idiom是一种实现隐藏的技术,其中公共类包装公共类所属的库外无法看到的结构或类。这会隐藏来自库用户的内部实现细节和数据。
但是可以实现相同的参考使用吗?
MCanvasFont.h
namespace Impl {
class FontDelegate;
}
class MCanvasFont
{
public:
MCanvasFont();
virtual ~MCanvasFont();
protected:
// Reference count
long m_cRef;
// agg font delegate
const Impl::FontDelegate& m_font;
}
MCanvasFont.cpp
// helpers
#include "ImplHelpers/FontDelegate.h"
MCanvasFont::MCanvasFont()
: m_cRef(1),
m_font(Impl::FontDelegate() )
{
// constructor's body
}
P.S。这段代码编译时没有任何G ++问题。
答案 0 :(得分:5)
程序中存在错误,它位于构造函数的初始化列表中:
MCanvasFont::MCanvasFont()
: m_cRef(1),
m_font(Impl::FontDelegate() ) // <--- BANG
{
Impl::FontDelegate()
的问题在于它构造了一个临时对象。这不会比构造函数更长 - 实际上它在进入构造函数体之前实际上已被销毁,因为它的生命周期是它出现的表达式的生命周期。因此,您的m_font
引用会立即失效。
虽然你的可能的使用手动分配的对象初始化它(*new Impl::FontDelegate()
)你在不确定的领土,如果除非你有你的运行时启用例外分配失败。无论如何,你仍然必须在你的析构函数中delete
对象。所以这个引用确实没有给你带来任何好处,它只是为了一些相当不自然的代码。我建议改为使用const指针:
const Impl::FontDelegate* const m_font;
编辑:为了说明问题,请使用此等效示例:
#include <iostream>
struct B
{
B() { std::cout << "B constructed\n"; }
~B() { std::cout << "B destroyed\n"; }
};
struct A
{
const B& b;
A() :
b(B())
{
std::cout << "A constructed\n";
}
void Foo()
{
std::cout << "A::Foo()\n";
}
~A()
{
std::cout << "A destroyed\n";
}
};
int main()
{
A a;
a.Foo();
}
如果你运行它,输出将是:
B constructed
B destroyed
A constructed
A::Foo()
A destroyed
所以b
几乎立即失效。