为什么不将所有内容都放在标题中?

时间:2018-10-22 12:06:11

标签: c++

我开始使用C ++,并且来自C和Java。我知道在C语言中强烈建议在标头中编写变量/类型/函数声明,并在源代码中编写变量/类型/函数定义。因此,当我开始使用C ++进行编码时,我也想遵循相同的约定。

不幸的是,在C ++中,该规则有几个例外:

  • 模板类;
  • 内联函数;
  • constexpr函数;

这使我对文件有些困惑:它们大多数是带有*.cpp文件的标头,其中包含很少的中/大型成员函数。

所以我的问题是:假设仅使用类而不是使用普通C进行编码,为什么我不能只将所有内容放在头文件中并且没有cpp文件?(某种Java样式) ;需要说明的是:我最多将不得不处理类,模板类,至多模板函数。

例如在Foo.hpp中:

class Foo {
public:
 foo() {
     //body
 }
 bar() {
     //body
 }
}

而不是在*.hpp*.cpp之间进行划分:

//file Foo.hpp
class Foo {
public:
 foo();
 bar();
}

//file Foo.cpp
Foo::foo() {
   //body
}
Foo::bar() {
   //body
}

当然会在.*cpp中放置诸如静态全局变量之类的东西,但是据我所知,它们是唯一需要放入cpps中的东西(并且强烈建议使用它们也不要气)。

能否请您告诉我这种方法的弱点是什么?作为C ++的初学者,我肯定会忽略一些重要因素。在我幼稚的观点中,cpp文件中不需要任何内容​​(假设我当然只使用类进行编码)。

谢谢

1 个答案:

答案 0 :(得分:5)

  

为什么我不能将所有内容都放在标题中并且没有cpp文件?

好吧,您必须至少有一个源文件,否则就没有任何可编译的内容。

但是,要回答,为什么不应该将所有内容都放在单个源文件中:因为该源文件的大小线性增加到整个程序的大小(拆分为头文件确实会不减小尺寸。相关的是预处理后的尺寸。因此,(重新)编译它的速度越来越慢,并且对该源文件的任何部分(即整个程序的任何部分,还包括标头)进行的任何更改都要求您重新编译该源文件(即整个程序)。

如果将程序拆分为多个源文件,则仅需要重新编译那些已修改的源文件。对于大型项目,这可以将编译时间减少到一分钟,这对于典型的工作流程为“编辑->编译->调试->编辑->编译-> ...”是一个福音。

动态链接可以进一步发挥这一优势:即使不重新链接,您也可以简单地替换动态库(只要新版本与ABI兼容)。


为了公平起见,让我也回答为什么应该将所有内容都放在单个源文件中:因为这从头开始减少了编译时间 。如果您的工作流程不适用于增量重建,那么稍微减少整个编译时间总比没有好。并且因为它允许更好的优化,因为编译器无法在源文件之间进行内联扩展(如果可以依靠链接时间优化,则链接时间优化可能会降低这一优势)。


理想的解决方案可能既不是在单个庞大的源文件中定义所有功能,也不是在每个单独的源文件中定义所有功能的理想选择。理想的选择可能介于两者之间。

一个典型的约定是每个类的成员函数只有一个源文件,但是并没有绝对的理由遵循该约定。在单个源文件中定义多个类的成员函数完全可以,也可以将一个类的定义成员函数划分为单独的文件,只要您有这样做的理由即可。


  

我认为这种方法将是“方便的”,因为您不再寻找函数:它位于cpp文件中;该死的:这是一个模板,所以它在标题中……非常令人沮丧!

与编译时间考虑因素相比,这不是一个有力的论据。开发环境可用(甚至是免费的,而且已经使用了数十年),使您可以在不到一秒钟的时间内跳转到函数声明(或调用)的定义。