根据我的阅读和理解,源文件中的#include
指令(例如ex main.cpp
)只是将包含文件的内容复制到.cpp
。因此,当我包含头文件时,例如yum.h
,yum.h
中的所有语句都会被复制到main.cpp
。
头文件只有声明,实际定义将在相应的.cpp
文件中,如yum.cpp
。
因此,在编译main.cpp
时,编译器如何知道查找yum.h
中yum.cpp
中提到的任何函数的定义?编译器如何知道如何编译yum.cpp
文件,因为main.cpp
文件或yum.h
中没有对它进行引用。
另外,为什么yum.h
中应包含yum.cpp
?
这听起来像是一个愚蠢的问题。我是OOP和C ++的初学者,我只是想了解发生了什么。
答案 0 :(得分:10)
简短回答:标题与其实现之间没有关系。一个可以在没有另一个的情况下存在,或者两者可以放在具有不相关名称的文件中。
编译
main.cpp
时编译器如何知道yum.h
中yum.cpp
中提到的任何函数的定义?
编译器不知道。每次它看到对yum.h
或任何其他头文件中声明的内容的引用时,它都会留意相应的定义。
如果编译器到达翻译单元结束时没有定义,则会将未满足的引用写入其main.o
输出,并注明它们来自的位置。这称为symbol table。
然后编译器编译yum.cpp
,从中查找yum.h
中的定义,并将其位置写入yum.o
的符号表。
处理完所有cpp
文件后,链接器会抓取所有.o
个文件,并从中构建一个组合符号表。如果仍有不满意的引用,则会发出错误。否则,它会将main.o
的引用与yum.o
中的相应符号相关联,从而完成整个过程。
考虑一个例子:让我们说yum.h
声明int yum = 0
中定义的全局变量yum.cpp
,main.cpp
打印该变量。编译器使用符号表生成main.o
"我需要在地址1234"处int yum
的定义,以及yum.o
文件的符号表说"我在地址9876" int yum
。链接器匹配"我需要"用"我有"将9876放在地址1234。
答案 1 :(得分:2)
编译器不需要在其他代码文件中查找任何内容 编译的结果是一个目标文件,它具有其他代码文件中定义的占位符。为了制作这些占位符,编译器只需要由合适的头文件(声明,原型等)提供的信息 填充占位符的步骤是链接器的工作,这在理论上是与编译器分开的工具。 (“理论上”如“可能是一个单独的工具,表现得像两个独立的工具。”
将包含声明的头文件包含在执行代码文件(全部或部分声明的内容)中的原因是一种广泛传播的最佳实践,因为它允许编译器在实现和声明不进行时进行投诉匹配。
答案 2 :(得分:2)
因此,在编译main.cpp时,编译器如何知道在yum.cpp中查找yum.h中提到的任何函数的定义?
编译器没有。当它产生目标文件(这是编译的结果)时它会说 - 调用函数等等。然后是链接过程,其中所有目标文件和库链接在一起以产生可执行文件。当链接器看到所有目标文件和库时,它知道在哪里找到该函数(或者如果找不到它就会产生错误)。
即编译器如何知道如何编译yum.cpp文件,因为main.cpp文件或yum.h文件中没有对它的引用。
编译器也不知道。程序员的工作是告诉编译器将所有必要的源文件编译成对象源文件并将它们全部传递给链接器。它可以在IDE内部完成,可能对您隐藏,或者您可能必须使用实用程序make
手动执行此操作。
为什么yum.h包含在yum.cpp中
编译C ++程序时,通常会有类及其方法。为了能够在其他源文件中使用它,它的定义必须在那里可见,所以它会转到标题。在.cpp文件中实现的方法也必须首先在类中声明,以便.cpp必须包含它的头。即使对于独立函数,让编译器将头中的签名与实现中的签名匹配也更简洁。