将 C 定义放在头文件中是一种好习惯吗?

新手上路,请多包涵

我对 C++ 的个人风格总是将类声明放在包含文件中,并将定义放在 .cpp 文件中,非常类似于 Loki 对 C++ Header Files, Code Separation 的回答中 规定的。诚然,我喜欢这种风格的部分原因可能与我多年来为 Modula-2 和 Ada 编写代码有关,它们都具有类似的规范文件和正文文件方案。

我有一个同事,他比我更懂 C++,他坚持所有 C++ 声明都应该在可能的情况下在头文件中包含定义。他并不是说这是一种有效的替代风格,或者甚至是更好的风格,而是说这是每个人现在都在 C++ 中使用的新的普遍接受的风格。

我不像以前那样灵活了,所以在我看到更多人和他在一起之前,我并不急于赶上他的这股潮流。那么这个成语到底有多普遍呢?

只是为了给答案一些结构:现在是 The Way™ ,非常常见,有点常见,不常见还是疯狂的错误?

原文由 T.E.D. 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 538
2 个回答

你的同事错了,常见的方法是并且一直都是将代码放在 .cpp 文件(或任何你喜欢的扩展名)中,并在标题中声明。

有时将代码放在头文件中会有一些好处,这可以让编译器更聪明地进行内联。但与此同时,它会破坏您的编译时间,因为每次编译器包含所有代码时都必须对其进行处理。

最后,当所有代码都是标题时,循环对象关系(有时是需要的)通常很烦人。

归根结底,你是对的,他是错的。

编辑: 我一直在考虑你的问题。有 一种 情况,他说的是真的。模板。许多较新的“现代”库(例如 boost)大量使用模板,并且通常是“仅标题”。但是,这只能在处理模板时进行,因为这是处理模板时的唯一方法。

编辑: 有些人想要更清楚一点,这里有一些关于编写“仅标题”代码的缺点的想法:

如果你四处搜索,你会看到很多人在处理 boost 时试图找到一种减少编译时间的方法。例如: 如何使用 Boost Asio 减少编译时间,它可以看到单个 1K 文件的 14 秒编译,其中包含 boost。 14 秒似乎没有“爆炸式增长”,但它肯定比典型的要长得多,并且在处理大型项目时可以很快加起来。仅标头库确实以可衡量的方式影响编译时间。我们只是容忍它,因为 boost 非常有用。

此外,还有很多事情不能仅在标头中完成(即使 boost 具有您需要链接到某些部分的库,例如线程、文件系统等)。一个主要的示例是,您不能在仅标头库中拥有简单的全局对象(除非您求助于单例的可恶),因为您将遇到多个定义错误。 注意: C++17 的内联变量将使这个特定示例在未来变得可行。

最后一点,当使用 boost 作为仅标头代码的示例时,经常会遗漏一个巨大的细节。

Boost 是库,而不是用户级代码。所以它不会经常改变。在用户代码中,如果你把所有东西都放在头文件中,每一个小改动都会导致你不得不重新编译整个项目。这是对时间的巨大浪费(对于不会从编译到编译的库来说,情况并非如此)。当您在标头/源之间拆分内容时,使用前向声明来减少包含,您可以在一天内加起来节省数小时的重新编译时间。

原文由 Evan Teran 发布,翻译遵循 CC BY-SA 4.0 许可协议

我认为将所有函数定义都放入头文件中绝对是荒谬的。为什么?因为头文件用作类的 PUBLIC 接口。这是“黑匣子”的外面。

当你需要查看一个类来参考如何使用它时,你应该查看头文件。头文件应该给出一个它可以做什么的列表(注释来描述如何使用每个函数的细节),它应该包括一个成员变量的列表。它不应该包括每个单独的功能是如何实现的,因为这是一堆不必要的信息,只会使头文件混乱。

原文由 SeanRamey 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题