为什么要把类放在实现文件中呢?

Why would you want to put a class in an implementation file?

本文关键字:文件 实现 为什么      更新时间:2023-10-16

在查看一些代码时,我遇到了以下问题:

. h文件
class ExampleClass
{
public:
    // methods, etc
private:
    class AnotherExampleClass* ptrToClass;
}

. cpp文件
class AnotherExampleClass
{
    // methods, etc
}
// AnotherExampleClass and ExampleClass implemented 

在c++中工作时,这是一种模式还是有益的东西?由于类没有分解到另一个文件中,这个工作流程是否可以提高更快的编译时间?

或者这只是这个开发者的风格?

这被称为pImpl习惯用法、柴郡猫技术或编译防火墙。

好处:

  • 更改类的私有成员变量不需要重新编译依赖于它的类,从而使时间更快,并且FragileBinaryInterfaceProblem减少
  • 头文件不需要#include在私有成员变量中"按值"使用的类,因此编译时间更快。
  • 这有点像SmallTalk自动处理类的方式…更纯的封装。

缺点:

  • 实现者的更多工作。
  • 对于需要子类访问的"protected"成员不起作用。
  • 有点难读代码,因为一些信息不再在头文件。
  • 运行时性能会因为指针间接而受到轻微的损害,特别是如果函数调用是虚拟的(间接分支的分支预测通常很差)。

Herb Sutter的《Exceptional c++》一书也详细介绍了如何正确使用这种技术。

最常见的例子是在使用PIMPL模式或类似技术时。不过,它还有其他用途。通常,c++中.hpp/.cpp的区别更像是(或者至少可以是)公共接口与私有实现的区别。如果一个类型只是作为实现的一部分使用,那么就有理由不把它导出到头文件中。

除了可能是PIMPL习惯用法的实现之外,这样做还有两个可能的原因:

c++中的

对象不能修改它们的this指针。因此,它们不能在使用过程中改变类型。然而,ptrToClass可以改变,允许delete本身的实现,并将其替换为AnotherExampleClass的另一个子类的另一个实例。

如果AnotherExampleClass的实现依赖于某些模板参数,而ExampleClass的接口不依赖,则可以使用从AnotherExampleClass派生的模板来提供实现。这对接口类的用户隐藏了部分必要的内部类型信息。