我对 C++ 的个人风格总是将类声明放在包含文件中,并将定义放在 .cpp
文件中,非常类似于 Loki 对 C++ Header Files, Code Separation 的回答中 规定的。诚然,我喜欢这种风格的部分原因可能与我多年来为 Modula-2 和 Ada 编写代码有关,它们都具有类似的规范文件和正文文件方案。
我有一个同事,他比我更懂 C++,他坚持所有 C++ 声明都应该在可能的情况下在头文件中包含定义。他并不是说这是一种有效的替代风格,或者甚至是更好的风格,而是说这是每个人现在都在 C++ 中使用的新的普遍接受的风格。
我不像以前那样灵活了,所以在我看到更多人和他在一起之前,我并不急于赶上他的这股潮流。那么这个成语到底有多普遍呢?
只是为了给答案一些结构:现在是 The Way™ ,非常常见,有点常见,不常见还是疯狂的错误?
原文由 T.E.D. 发布,翻译遵循 CC BY-SA 4.0 许可协议
你的同事错了,常见的方法是并且一直都是将代码放在 .cpp 文件(或任何你喜欢的扩展名)中,并在标题中声明。
有时将代码放在头文件中会有一些好处,这可以让编译器更聪明地进行内联。但与此同时,它会破坏您的编译时间,因为每次编译器包含所有代码时都必须对其进行处理。
最后,当所有代码都是标题时,循环对象关系(有时是需要的)通常很烦人。
归根结底,你是对的,他是错的。
编辑: 我一直在考虑你的问题。有 一种 情况,他说的是真的。模板。许多较新的“现代”库(例如 boost)大量使用模板,并且通常是“仅标题”。但是,这只能在处理模板时进行,因为这是处理模板时的唯一方法。
编辑: 有些人想要更清楚一点,这里有一些关于编写“仅标题”代码的缺点的想法:
如果你四处搜索,你会看到很多人在处理 boost 时试图找到一种减少编译时间的方法。例如: 如何使用 Boost Asio 减少编译时间,它可以看到单个 1K 文件的 14 秒编译,其中包含 boost。 14 秒似乎没有“爆炸式增长”,但它肯定比典型的要长得多,并且在处理大型项目时可以很快加起来。仅标头库确实以可衡量的方式影响编译时间。我们只是容忍它,因为 boost 非常有用。
此外,还有很多事情不能仅在标头中完成(即使 boost 具有您需要链接到某些部分的库,例如线程、文件系统等)。一个主要的示例是,您不能在仅标头库中拥有简单的全局对象(除非您求助于单例的可恶),因为您将遇到多个定义错误。 注意: C++17 的内联变量将使这个特定示例在未来变得可行。
最后一点,当使用 boost 作为仅标头代码的示例时,经常会遗漏一个巨大的细节。
Boost 是库,而不是用户级代码。所以它不会经常改变。在用户代码中,如果你把所有东西都放在头文件中,每一个小改动都会导致你不得不重新编译整个项目。这是对时间的巨大浪费(对于不会从编译到编译的库来说,情况并非如此)。当您在标头/源之间拆分内容时,使用前向声明来减少包含,您可以在一天内加起来节省数小时的重新编译时间。