C++包含文件

C++ Include files

本文关键字:文件 包含 C++      更新时间:2023-10-16

我知道在头文件中提供定义允许其他文件引用它们,然后链接器将所有对象文件添加在一起,稍后提供定义。

这只是为了让我们可以在其他库中的其他地方重用实现吗?

如果我们不使用头文件或滥用它们,并将所有代码都放在其中,即完整的实现会发生什么?编译每个文件时会花费更长的时间吗?因为完整的定义需要在对等文件的基础上编译?它会不会导致链接器出现问题,因为同一实现会有多个编译版本?

如何使用模板?

布莱尔

每当新的编译目标包括头文件时,放置在头文件中的任何代码都会被编译,所以至少是的,编译时间会更长。不过,一般来说,这并不是什么大问题。

假设你有这个标题:

int f_header() {
return 0;
}

这些源文件:

/* a.cpp */
#include "myheader.h"
int f_a() {
return f_header();
}

/* b.cpp */
#include "myheader.h"
int f_b() {
return f_header();
}

现在,当您编译这些源中的每一个时,编译就会成功。但是,当您链接程序时,链接器将失败,因为您将提供两次函数f_header()

模板是一种特殊情况,因为它们实际上不是代码,而是为基于不同类型生成的代码提供了一个模板。尽管当多个源文件使用相同类型的文件时会出现重复,但编译器能够为您处理这种特殊情况。

拆分源文件和头文件中的代码在历史上或多或少是必需的。它允许编译器单独编译大型项目的代码单元,因为整个项目太大,无法同时编译。

它还允许缓存未更改的编译单元,这进一步缩短了编译时间。

因此,从技术上讲,编译器可以看到一整套不同的编译单元。如果您提供了同一定义的多个实现,编译器就无法告诉您。但是,一旦链接器将编译后的单元打包为一个可执行文件,它就会被它绊倒。

今天,像C#或Java这样的"现代"语言摆脱了这种历史限制。但是C++是一种复杂的语言,即使对于编译器来说也是如此,所以这些优势在某种程度上仍然是相关的。

编译器一次编译一个文件。编译器正在解析的源文件可能包括其他文件,但在预编译阶段,所有这些包含的文件都被"展平"为单个源,编译器"看到"一个单独的代码实体。

由于以上原因,对于编译器来说,代码是在.cpp文件中还是在.h文件中并不重要,因为编译器不进行区分。但是,如果一些函数定义或变量定义在.h文件中,则问题会在链接阶段出现。

链接器看不到源文件,但它看到了对象文件(.obj),这是编译器生成的结果。链接器知道每个对象文件中的每个函数和每个变量,链接器的工作是将它们绑定(或链接)在一个可执行文件中。如果在不同的对象文件中有几个具有相同名称的变量或函数,链接器将不知道该如何处理它们,并且它将声明一个错误。可以通过一个选项强制链接器忽略所有额外的变量和函数,但该选项不能轻易使用。两个同名的函数实际上可能完全不同,忽略其中一个会导致各种错误。

另一方面,模板根本不是函数。它们是实际功能的蓝图。当编译器遇到模板时,不会发生实质性的事情。只有当模板被实例化为实际函数时,编译器才会生成这样的函数。正因为如此,模板可以驻留在头文件中。