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