PIMPL习语VS前向声明

时间:2016-03-16 06:19:13

标签: c++ pimpl-idiom

我已经阅读了一些有关PIMPL惯用语的内容并且想知道 - 转发声明依赖类型有什么不同吗?

如果是这样的话:

  • 我什么时候更喜欢使用它而不是前方声明?
  • 这两个版本的编译时间是否不同?
  • 其中一个比另一个更具可扩展性吗?

具体考虑依赖于Foo的类Bar(应该有Bar类型的成员。)

带有前瞻声明的

Foo.h

class Bar;

class Foo
{
public:
    Foo();

private:
    Bar* _bar;
};
带有PIMPL的

Foo.h

class Foo
{
    public:
        Foo();

    private:
        /* FooImpl is an incomplete type at this point.
         * Implemented in cpp file and has a member of type Bar.
         */
        class FooImpl;  

        FooImpl* _fooImpl;
}

请忽略原始指针的用法 - 我只是想点一下

2 个答案:

答案 0 :(得分:4)

PIMPL模式通常用于完全隐藏使用您的类的代码的实现细节。

例如,您的类可能包含特定于平台的功能。即使您使用了前向声明和/或条件编译,您最终也会在头文件中公开特定于平台的代码。这意味着使用您的类的任何代码最终都会依赖于这些类型的标头依赖性,这意味着您的类可能会根据平台而发生变化(例如,大小可能不同)。

PIMPL模式允许您将所有特定于平台的详细信息隐藏在实现文件中(通常为* .cpp或类似)。这意味着程序中任何其他地方的其他代码都无法直接看到它,从而使您的包装类在所有平台上保持干净和一致。

这只是PIMPL派上用场的一个例子,但它也有其他用途。

值得注意的是,并非所有内容都可以向前声明,并且前向声明通常需要做出不受欢迎的让步,例如在任何地方使用指针或引用。

答案 1 :(得分:4)

  

我已经阅读了一些有关PIMPL惯用语的内容并且想知道 - 转发声明依赖类型有什么不同吗?

是的,他们是不同的。 PIMPL idiom(它有several names)专门用于隐藏客户端代码中的实现细节。这可以出于多种原因,包括(但不限于);

  • 在课程详细信息更改时隐藏重建(隐藏)
  • 最小化所需或冲突的标题包含
  • 缩短一般构建时间
  • 最小出口要求(尽管抽象类也可用于此目的)
  • 更轻松地控制因多个目标或平台而异的实施细节

从本质上讲,PIMPL提供了一种从客户端代码“隐藏”实现的技术 - 只要可能需要。

  

我什么时候更喜欢使用[PIMPL]而不是前向声明?

这真的是关于意图 - 你的代码是关于抽象 - 照顾那些抽象,保护它们并保护它们,它们会很好地为你服务。

问题变成了 - 哪一个更能代表你的意图?我冒昧地说FooImpl更好,我觉得你的意图是从客户端隐藏类的实现,这个实现更能代表那个意图(因为客户端无法访问FooImpl )。

如果您打算在类Bar之外的代码中的其他位置使用Foo,那么该实现更好,因为这是意图,并且该实现允许您这样做。 / p>

  

这两个版本的编译时间是否不同?

我对此表示怀疑。 BarFooImpl的实施在其定义的翻译单元之外不可见。

  

其中一个比另一个更具可扩展性吗?

不是,不。在一般意义上,更清晰的代码是,人们能够更容易地扩展它。