PIMPL 习惯用法是一种实现隐藏技术,其中公共类包装了在公共类所属的库外部无法看到的结构或类。这对库的用户隐藏了内部实现细节和数据。
但是是否可以利用参考来实现相同的功能?
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
}
附:这段代码用 G++ 编译没有任何问题。
您的程序中有一个错误,它位于构造函数的初始化列表中:
MCanvasFont::MCanvasFont()
: m_cRef(1),
m_font(Impl::FontDelegate() ) // <--- BANG
{
问题在于Impl::FontDelegate()
是它构建了一个暂时的目的。这不会比构造函数的寿命更长 - 事实上,它实际上在进入构造函数主体之前被销毁,因为它的生命周期是它出现的表达式的生命周期。因此你的m_font
参考立即无效。
当你could使用手动分配的对象初始化它(*new Impl::FontDelegate()
)如果分配失败,除非您在运行时启用了异常,否则您将处于未定义的区域。你还必须delete
无论如何,你的析构函数中的对象。因此,该参考实际上不会给您带来任何优势,它只会产生一些相当不自然的代码。我建议改用 const 指针:
const Impl::FontDelegate* const m_font;
EDIT:为了说明这个问题,举这个等效的例子:
#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
So b
几乎立即无效。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)