大型 C++ 项目中的一个问题可能是构建时间。您的依赖树中有一些类需要处理,但通常您会避免这样做,因为每次构建都需要很长时间。您不一定要更改其公共接口,但也许您想更改其私有成员(添加缓存变量,提取私有方法,...)。您面临的问题是,在 C++ 中,即使私有成员也是在公共头文件中声明的,因此您的构建系统需要重新编译所有内容。

在这种情况下你会怎么做?

我已经概述了我所知道的两种解决方案,但它们都有其缺点,也许还有一个我还没有想到的更好的解决方案。

有帮助吗?

解决方案

痘痘图案:

在头文件中,仅声明公共方法和指向前向声明的实现类的私有指针(pimpl 指针或委托)。

在源代码中,声明实现类,将公共类的每个公共方法转发给委托,并在公共类的每个构造函数中构造 pimpl 类的实例。

加:

  • 允许您更改类的实现,而无需重新编译所有内容。
  • 继承效果很好,只是语法略有不同。

减:

  • 要编写很多很多愚蠢的方法体来进行委托。
  • 调试起来有点尴尬,因为你有大量的代表需要逐步执行。
  • 基类中的额外指针,如果您有很多小对象,这可能会成为问题。

其他提示

约翰洛科什大规模C ++软件设计是解决一个很好的书参与建设大型C ++项目的挑战。存在的问题和解决方案都立足于现实,肯定了上述问题详细讨论。强烈推荐。

使用继承:

在标头中,将公共方法声明为纯虚拟方法和工厂。

在您的源代码中,从您的接口派生一个实现类并实现它。在执行工厂中返回一个执行实例。

加:

  • 允许您更改类的实现,而无需重新编译所有内容。
  • 实施起来简单又万无一失。

减:

  • 定义公共基类的(公共)派生实例确实很尴尬,它应该继承公共基类的(私有)实现的一些方法。

您可以对类 A 使用前向声明,该声明由另一个类 B 中的指针引用。然后,您可以将类的 A 头文件包含在类 B 的实现文件中,而不是其头文件中。这样,您对 A 类所做的更改将不会影响包含 B 类头文件的源文件。任何想要访问 A 类成员的类都必须包含 A 类的头文件。

重构和使用PIMPL /柄体成语,用纯虚拟接口隐藏实现细节似乎是普遍回答。每个人都应该考虑设计大型系统时,编译时间和开发人员的生产力。但如果你对现有的大型C ++系统没有单元测试覆盖率的工作是什么?重构通常是不可能的。

我最常做的时候我不想让编译器编译后的世界我感动的一些常见的头文件是有一个生成文件/脚本编译只有我自己知道需要重新编译的文件。例如,如果我加入一个非虚拟专用功能的一类,只有类的CPP文件需要,即使其头文件是由一百其他文件包括重新编译。在我离开的一天,我开球干净的构建,以重建世界。

没有任何。

我明白使用一个的意义,但我认为以下论点在许多情况下减轻了这一点:

  1. 清晰度是第一位的。如果必须考虑两次对运行时速度的明确性,那么妥协的清晰度如何编译时间 速度?
  2. 私人成员不应该经常更换。
  3. 通常,不需要 渴望重建一切。
  4. 未来将会出现更快的工具,因此编译速度问题将自动得到缓解。您的代码不会自动变得更清晰。
  5. 无论如何,你应该经常重建。
  6. 你有没有尝试过 英科迪建筑?

当然,最终这是一个经济决定。如果“3”的权重在您的项目中很重要,并且由于某种原因“6”无法应用,那么请继续:使用这些模板,您获得的收益将多于您损失的收益。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top