c++ 为什么我们包括头文件而不是源文件?

9wbgstp7  于 2023-11-19  发布在  其他
关注(0)|答案(2)|浏览(131)

下面是一个例子。如果我在一个名为Bob.hvoid PrintSomething();的头文件和.cpp文件中声明一个函数,我说:void MyClass::PrintSomething(){std::cout << "Hello";}。我在另一个.cpp文件中看到过,例如Frank.cpp,只包含Bob.h头,它只有声明(里面没有代码),而不是.cpp的代码,但让我震惊的是,当他们调用Frank.cpp中的PrintSomething()函数时,它使用了Bob.cpp中的代码并打印“Hello”怎么会?当我只包含了.h文件,而这个文件并没有说任何关于“Hello”的事情,它只是一个声明时,它是如何打印“Hello”的呢?我已经看过了编译过程和链接过程,但它就是不坚持。
最重要的是,如果我现在在我的Frank.cpp文件中说:void MyClass::PrintSomething(){std::cout << "Bye";},并将Bob.h文件包含在我的main.cpp中,并调用PrintSomething()函数,它会打印“Hello”还是“Bye”?计算机是通灵的还是什么?这个概念是我在C++学习过程中没有掌握的一件事。

nmpmafwu

nmpmafwu1#

在你包含Bob.h的那一刻,编译器已经拥有了它需要知道的关于PrintSomething()的一切,它只需要一个函数的声明。Frank.cpp不需要知道定义PrintSomething()Bob.cpp
所有的cpp文件都输出编译器生成的目标文件,这些文件本身并没有多大作用,直到它们都粘在一起,这是链接器的责任。
链接器获取所有对象文件并填充缺少的部分:
Linker talk:
嘿,我看到Frank.obj使用了PrintSomething(),但我在对象文件中看不到它的定义。
让我们检查其他目标文件。
在检查Bob.obj时,我可以看到它包含了PrintSomething()的可用定义,让我们使用它。
这当然是简化的,但这就是链接器所做的。
在此之后,您将获得可用的可执行文件。
在此之上,如果我现在在我的Frank.cpp文件中说:void MyClass::PrintSomething(){std::cout << "Bye";},并将Bob.h文件包含在我的main.cpp中,并调用PrintSomething()函数,它会打印“Hello”或“Bye”吗?
链接器会找到PrintSomething()的2个定义,并发出错误,它无法知道选择哪个定义是正确的。

mepcadol

mepcadol2#

这里的关键概念是单独编译。您将项目划分为一组实现或多或少独立内容的源文件,将这些源文件编译为目标文件,然后链接目标文件和任何其他库(包括标准库)来创建可执行文件。对于大型项目,编译所有源文件可能需要很长时间(有时以小时为单位)。第一次构建应用程序时必须这样做。但在此之后,如果您只更改了一个源文件,则只需重新编译该源文件,然后再次链接,这是你第一次创建的目标文件。这通常是一个很大的时间节省。如果你有一个巨大的源文件,(也就是说,一个#include是所有其他源文件的源文件),你没有这个选项--你必须每次都重新编译整个文件。

相关问题