我开始使用C ++,并且来自C和Java。我知道在C语言中强烈建议在标头中编写变量/类型/函数声明,并在源代码中编写变量/类型/函数定义。因此,当我开始使用C ++进行编码时,我也想遵循相同的约定。
不幸的是,在C ++中,该规则有几个例外:
这使我对文件有些困惑:它们大多数是带有*.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文件中不需要任何内容(假设我当然只使用类进行编码)。
谢谢
答案 0 :(得分:5)
为什么我不能将所有内容都放在标题中并且没有cpp文件?
好吧,您必须至少有一个源文件,否则就没有任何可编译的内容。
但是,要回答,为什么不应该将所有内容都放在单个源文件中:因为该源文件的大小线性增加到整个程序的大小(拆分为头文件确实会不减小尺寸。相关的是预处理后的尺寸。因此,(重新)编译它的速度越来越慢,并且对该源文件的任何部分(即整个程序的任何部分,还包括标头)进行的任何更改都要求您重新编译该源文件(即整个程序)。
如果将程序拆分为多个源文件,则仅需要重新编译那些已修改的源文件。对于大型项目,这可以将编译时间减少到一分钟,这对于典型的工作流程为“编辑->编译->调试->编辑->编译-> ...”是一个福音。
动态链接可以进一步发挥这一优势:即使不重新链接,您也可以简单地替换动态库(只要新版本与ABI兼容)。
为了公平起见,让我也回答为什么应该将所有内容都放在单个源文件中:因为这从头开始减少了编译时间 。如果您的工作流程不适用于增量重建,那么稍微减少整个编译时间总比没有好。并且因为它允许更好的优化,因为编译器无法在源文件之间进行内联扩展(如果可以依靠链接时间优化,则链接时间优化可能会降低这一优势)。
理想的解决方案可能既不是在单个庞大的源文件中定义所有功能,也不是在每个单独的源文件中定义所有功能的理想选择。理想的选择可能介于两者之间。
一个典型的约定是每个类的成员函数只有一个源文件,但是并没有绝对的理由遵循该约定。在单个源文件中定义多个类的成员函数完全可以,也可以将一个类的定义成员函数划分为单独的文件,只要您有这样做的理由即可。
我认为这种方法将是“方便的”,因为您不再寻找函数:它位于cpp文件中;该死的:这是一个模板,所以它在标题中……非常令人沮丧!
与编译时间考虑因素相比,这不是一个有力的论据。开发环境可用(甚至是免费的,而且已经使用了数十年),使您可以在不到一秒钟的时间内跳转到函数声明(或调用)的定义。