PIMPL 成语 VS 前向声明

Mr.*_*son 2 c++ pimpl-idiom

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

如果是这样的话:

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

特别考虑一个Foo依赖于Bar(应该有一个 type 成员)的类Bar

Foo.h 带有前向声明:

class Bar;

class Foo
{
public:
    Foo();

private:
    Bar* _bar;
};
Run Code Online (Sandbox Code Playgroud)

Foo.h 与 PIMPL:

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;
}
Run Code Online (Sandbox Code Playgroud)

请忽略原始指针的使用 - 我只是想说明一点

Nia*_*all 5

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

是的,它们是不同的。该PIMPL方法(它有好几个名字)是专门关于隐藏从客户端代码的实现细节。这样做的原因有很多,包括(但不限于);

  • 当类细节改变时隔离重建(它们被隐藏)
  • 最小化所需或冲突的标头包含
  • 一般的构建时间减少
  • 最小的导出要求(尽管抽象类也可以用于此目的)
  • 更容易控制在多个目标或平台上变化的实现细节

本质上,PIMPL 提供了一种技术,可以在需要时从客户端代码“隐藏”实现。

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

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

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

如果您的意图是Bar在代码中的其他地方使用,在 class 之外Foo,那么该实现会更好,因为这就是意图,并且该实现允许您这样做。

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

我不信。的实施BarFooImpl不可见之外,只在定义翻译单元。

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

不是真的,不是。从某种意义上说,代码越清晰,人们就越容易扩展它。