将方法放在.h与.cpp文件中

时间:2010-12-08 05:17:13

标签: c++ optimization compiler-construction header

我已经看到将类的代码放入单独的C ++中,而方法定义则放在头文件中。我的第一个OOP经验是使用Java,其中所有方法都放在类文件中,我实际上更喜欢这个。

将所有方法放在头文件中是否会影响编译器生成的汇编代码?

如果是这样,将一个类的整个代码放在头文件中对性能有害吗?

3 个答案:

答案 0 :(得分:6)

重点是复杂的C ++程序是通过编译多个对象,然后将它们链接在一起而创建的。每个对象通常来自编译一个实现文件(例如“.cpp”,“。cc”等),其可以直接和间接地包括许多头部。因此,如果你编写一个好类并将代码放入头中,那么该代码可以包含在多个目标文件中,然后编译器会冗余地生成它,而且 - 链接器不会(并且不能轻易地)比较查看它们是否相同的版本并删除冗余副本(如果使用相对地址则更容易 - “位置无关代码” - 但这是另一个故事)。另见jalf的评论如下。

因此,您不希望标题中包含不同的外部函数。如果它们名义上是inline函数 - 由于使用了inline关键字或在类中定义 - 那么编译器将只需承担额外的工作并确保它们的任何外联版本都是唯一表示在可执行文件中。但是,对于脱机功能,程序员仍然有负担。

此外,如果在头文件中提供实现,则会为每个对象进行冗余编译,对头文件的任何更改都将强制重新编译所有的从属对象。可以更改单独对象中的外部函数,重新编译单个对象,然后可以将其与其他预先存在的对象链接以形成新的可执行文件。在大型项目中,这节省了大量的编译时间。

答案 1 :(得分:2)

标头/实现拆分有几个正当理由 单独编译:
1。这可能是一项工作要求 - 例如,您提供的是 二进制库+标题给某人,或者你的同事太保守了 接受别的。
2。它仍然需要开发非常大的项目(例如,> 10M的源), 因为在每次修改后重建整个应用程序会变得很痛苦。 (但是将jpeglib或zlib作为单个模块编译仍然可以)
3。有一种观点认为它更易于使用头文件作为参考 功能等。 (但通常最好写一个适当的文档;与标题不同,文档中的错误不太可能影响你的程序)

此外,还有更多理由不再使用它:
1。您希望避免维护重复的代码。
2。类方法不需要前向声明
3。模板只能在标题中声明
4。你不需要函数内联的情况实际上相当罕见, 即在紧密循环中多次调用大型函数,但有 noinline attibutes和PGO。否则内联提高了速度。 至于编码臃肿,大多数图书馆无论如何都已经很大了。
5。总体而言,作为单一来源编制的程序更快,更小, 因为编译器可以做得更好。
6。没有标题,源通常会小两倍, 和编译器将能够正确检查语法,因此您将无法 意外地将extern“C”cdecl函数原型链接到变量作为实现。 总的来说,它会更便携,因为不同的链接器对名称匹配有不同的想法。
7。它奇怪,但动态分配经常被使用只是因为 标题样式 - 依赖关系可以通过定义所有的自动解决 单个类中的细节,但人们更喜欢使用指向部分类声明的指针(然后捕获内存泄漏)。

现在,单独的对象模块的一些奖励点:
4。每个对象模块生成gcc中的PGO统计信息,这似乎是使用单个可执行文件“基准”几个不同操作模式的唯一方法。
5。可以使用不同的编译器选项编译不同的模块以进行速度优化。还有一些编译器扩展,但它们不是很可靠。
6。有时,当您修改某些内容时,编译器可以对代码的另一部分做一些奇怪的事情 - 但通常它不能在对象模块之外传播。

答案 2 :(得分:1)

是的,标题中的方法是内联的,所以它们通常更快(特别是短的)。

主要缺点是标头中的每个修改都会导致重新编译包含它的每个文件。