标准和编译器并不真正关心文件是.cpp
or.h
还是.monkeyface
. 将源代码结构化为实现和头文件背后的概念实际上只是帮助管理源代码的公认方法。尽管如此,不以公认的方式构建源代码通常被认为是不正确或糟糕的 C++。
所做的只是告诉预处理器将您指定的文件的内容包含在#include
当前文件中。这就像将其他文件复制并粘贴到您的文件中一样。当您说#include "foo.h"
时,它只包含 的内容foo.h
并且根本不关心foo.cpp
- 它甚至不知道它存在(并且没有理由必须存在)。
在实现和头文件中构建源代码非常有用 - 它避免了依赖项和多个定义的问题,并且还可以在一定程度上缩短编译时间。当您的代码使用另一个类时,您只需要该类#include
的头文件。原因是您的代码不需要关心类的实现,它只需要知道它的样子(它的名称、成员、基类等)。它不关心成员函数是如何实现的。
扩展.cpp
和.h
仅仅是约定。有些人喜欢使用.hpp
头文件。有些人甚至使用.tpp
模板实现。您可以随意命名它们 - 是的,您甚至可以包含一个.txt
文件。您的编译器可能会尝试从文件扩展名推断有关文件的内容(例如,将其编译为哪种语言),但这通常是可覆盖的。
因此,如果您main.cpp
包含foo.h
因为它使用 class foo
,那么在什么时候foo.cpp
参与?好吧,在编译中main.cpp
,它根本不涉及。main.cpp
不需要知道类的实现,就像我们上面讨论的那样。但是,在编译整个程序时,您会将每个.cpp
文件传递给编译器以单独编译。也就是说,你会做类似的事情g++ main.cpp foo.cpp
。编译时foo.cpp
,它将包含它需要编译的头文件。
在您的每个.cpp
文件都被编译后(包括包括它们所依赖的头文件),然后将它们链接在一起。在这个阶段,成员函数的使用foo::bar()
将main.cpp
与 中foo::bar()
给出的实现相关联foo.cpp
。