2

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
}

PS 这段代码用 G++ 编译没有任何问题。

4

1 回答 1

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几乎立即无效。

于 2012-05-28T12:07:50.097 回答