PIMPL 成语 VS 前向声明
PIMPL idiom VS forward declaration
我已经阅读了一些关于 PIMPL 习语的内容,并想知道 - 转发声明依赖类型有什么不同吗?
㞖:
- 我什么时候更喜欢使用它而不是前向声明?
- 这两个版本的编译时间是否不同?
- 其中一个是否比另一个更具可扩展性?
具体考虑依赖于Bar
的类Foo
(应具有类型 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;
}
请忽略原始指针的使用 - 我只是想提出一个观点。
我已经阅读了一些关于 PIMPL 习语的信息,并且想知道 - 转发声明依赖类型有什么不同吗?
是的,它们是不同的。PIMPL 习惯用法(它有几个名称)专门用于从客户端代码中隐藏实现详细信息。这样做可能有多种原因,包括(但不限于);
- 在类详细信息更改时隔离重建(它们被隐藏)
- 最大限度地减少必需或冲突的标头包含
- 一般构建时间缩短
- 最低导出要求(尽管抽象类也可以用于此目的)
- 更轻松地控制因多个目标或平台而异的实施细节
从本质上讲,PIMPL 提供了一种从客户端代码中"隐藏"实现的技术 - 无论何时需要。
我什么时候更喜欢使用 [PIMPL] 而不是前向声明?
这实际上是关于意图的 - 你的代码是关于抽象的 - 照顾这些抽象,培育和保护它们,它们将很好地为你服务。
问题变成了 - 哪一个更能代表您的意图?我冒昧地说FooImpl
更好,我感觉到您的意图是对客户端隐藏类的实现,并且此实现更好地代表了该意图(因为客户端无法访问FooImpl
)。
如果你的目的是在代码中的其他地方使用Bar
,在类Foo
之外,那么该实现更好,因为这是意图,并且该实现允许您这样做。
这两个版本的编译时间是否不同?
我对此表示怀疑。Bar
和FooImpl
的实现在定义它们的翻译单元之外不可见。
其中一个是否比另一个更具可扩展性?
不是真的,不是。从某种通用意义上讲,代码越清晰,人们就越容易扩展它。
PIMPL 模式通常用于完全隐藏使用类的代码的实现详细信息。
例如,您的类可能正在包装特定于平台的功能。即使使用了前向声明和/或条件编译,最终也会在头文件中公开特定于平台的代码。这意味着使用您的类的任何代码最终也会依赖于这些类型的标头,这意味着您的类可能会根据平台而更改(例如,大小可能不同)。
PIMPL 模式允许您将所有特定于平台的详细信息隐藏在实现文件中(通常为 *.cpp 或类似文件)。这意味着程序中其他任何地方的其他代码都无法直接看到它,从而在所有平台上保持包装类的干净和一致。
这只是PIMPL派上用场的一个例子,但它还有其他用途。
还值得注意的是,并非所有内容都可以向前声明,并且前向声明通常需要做出不希望的让步,例如在任何地方使用指针或引用。
- .cpp和.h文件中的模板专用化声明
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 未在作用域中声明unordered_map
- C++不正确,不需要重新声明类成员变量 MFC 手工解决方案/项目 MS VS 2015
- CLANG VS GCC 模板子类在父级中使用前向声明的类
- Clang(OS X)要求在特定嵌套声明中"template"关键字,而VS禁止它
- PIMPL 成语 VS 前向声明
- C++函数模板专用声明和模板参数;无 vs. <> vs. <type>
- 传递的参数vs.变量声明
- __cdecl _unlock在声明指向指针的点抛出线程错误时与 VS C++ 2010 有问题
- c++ 11:显式实例化声明vs显式实例化定义
- VS 2012中的显式模板声明/定义
- 内联函数原型vs正则声明vs原型
- C/ c++前向声明vs. Include
- 无法在VS 14 CTP中使用auto声明lambda:类型为'void'的条件表达式是非法的
- 模板化类成员VS嵌套类前向声明
- OpenMP对性能的影响:私有指令vs.在构造中声明变量
- c++ include vs前向声明策略
- c++中的正向声明VS编译顺序错误,以避免包含递归标头
- 当场创建对象vs变量声明