您使用什么模式来分离C ++中的接口和实现?

时间:2009-06-09 23:24:08

标签: c++ delegation pimpl-idiom

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

在这种情况下你做了什么?

我已经勾画了两个我所知道的解决方案,但它们都有缺点,也许还有一个我还没有想过的更好的解决方案。

6 个答案:

答案 0 :(得分:9)

pimpl模式:

在头文件中,只将public方法和私有指针(pimpl-pointer或delegate)声明为前向声明的实现类。

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

加:

  • 允许您更改类的实现,而无需重新编译所有内容。
  • 继承运行良好,只有语法变得有点不同。

减:

  • 要写代理的很多愚蠢的方法体。
  • 由于你有大量的代表需要逐步完成调试,所以很难调试。
  • 基类中的额外指针,如果您有许多小对象,这可能是个问题。

答案 1 :(得分:6)

John Lakos'Large Scale C++ Software Design是一本很好的书,它解决了构建大型C ++项目所涉及的挑战。问题和解决方案都是以现实为基础的,当然也会详细讨论上述问题。强烈推荐。

答案 2 :(得分:2)

使用继承:

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

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

加:

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

减:

  • 非常难以定义公共基类的(公共)派生实例,该实例应该继承公共基础(私有)实现的一些方法。

答案 3 :(得分:0)

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

答案 4 :(得分:0)

重构和使用pimpl / handle-body惯用法,使用纯虚拟接口来隐藏实现细节似乎是最受欢迎的答案。在设计大型系统时,应考虑编译时和开发人员的工作效率。但是,如果您正在处理没有单元测试覆盖的现有大型C ++系统,该怎么办?重构通常是不可能的。

当我触摸一些常见的头文件后,当我不希望编译器编译世界时,我通常会做的是让makefile /脚本只编译我知道需要重新编译的文件。例如,如果我向类中添加非虚拟私有函数,则只需要重新编译类的cpp文件,即使其头文件包含在其他一百个文件中也是如此。在我离开这一天之前,我开始了一个干净的构建来重建世界。

答案 5 :(得分:0)

<强>无

我看到使用一个的重点,但我认为以下论点在许多场景中缓解了这一点:

  1. 首先是清晰度。如果损害运行时的清晰度 速度必须考虑两倍,什么 关于妥协的清晰度 编译时间速度?
  2. 私人成员不应经常更改。
  3. 通常情况下, 不需要重建所有内容。
  4. 将来会有更快的工具,因此编译速度问题将自动缓解。您的代码不会自动更清晰。
  5. 无论如何,你应该经常重建。
  6. 您是否尝试过Incredibuild
  7. 当然,这是一个经济决策。如果“3”的重量在您的项目中很重要且由于某种原因“6”不能适用,那么请继续:使用这些模板将比赢得更多赢得更多。