2.8 - 多文件程序
在项目中添加文件
随着程序规模不断增大,程序通常会被分割为多个文件以方便组织程序或增强其可复用性。使用 IDE 可以让组织多文件项目变得更加容易。我们已经学习了如何去创建并编译一个单文件项目,为这个项目添加一个文件是非常简单的。
最佳实践
在为项目添加代码文件时,请使用 .cpp
作为扩展名。
For Visual Studio users
在 Visual Studio 中,在解决方案浏览器窗口(Solution Explorer)右键点击 Source Files 目录并选择 Add > New Item….
选择 C++ File (.cpp)。为其指定一个文件名,就可以将文件添加到项目中。
注意:如果你是从 File 菜单而不是 Solution Explorer 窗口创建的文件,那么该文件不会被自动添加到项目中。因此你必须在解决方案浏览器窗口(Solution Explorer)右键点击 Source Files 目录并选择 Add > Existing Item,然后选择刚才创建的文件。
接下来,在编译程序的时候,你会发现编译器会将该文件列出来,因为它会对其进行编译。
For Code:: Blocks users
在 Code:: Blocks 中,在 File 菜单中选择 New > File…。
在 New from template 对话框中,选择 C/C++ source 并点击 Go。
你可能会来到一个 welcome to the C/C++ source file wizard 对话框。此时点击 Next。
在向导的下一个页面中,选择 “C++” 并点击 Next。
接下来,为这个新文件起一个名字(不要忘了使用 .cpp
作为后缀名),然后点击 All 按钮确保所有的构建目标都被勾选了。最后,选择 finish。
现在,当你编译程序的时候,你就可以看到编译器在编译时列出了该文件的名字。
For GCC/G++ users
你可以从命令行来创建文件并为其指定一个文件名。在编译程序的时候,你必须将相关的文件都包含在编译命令中。g++ main.cpp add.cpp -o main
, 其中,main.cpp
和 add.cpp
是需要编译的文件,main
则是输出文件的文件名。
一个多文件程序的例子
在 2.7 - 前向声明和定义中,我们介绍了一个单文件不能编译的例子:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
在编译器解析到第五行的 add
函数调用时,编译器不知道 add
为何物,因为我们还没有定义它呀!之前我们解决这个问题时使用了两种方案,要么重新调整函数定义的顺序,要么使用前向声明(forward declaration)。
现在,来看一个类似的多文件程序:
add.cpp:
1 2 3 4 |
|
main.cpp:
1 2 3 4 5 6 7 |
|
你的编译器可能会先编译 add.cpp 或者先编译 main.cpp。不论是那种情况,编译器都会报告和之前一样的编译错误:
1 |
|
问题的原因也是一样的,在编译器解析到第五行的 add
函数调用时,编译器不知道 add
为何物。
还记得吗?编译器是单独编译各个文件的,它并不知道其他代码文件中的内容,也不会记得之前编译时遇到的东西。也许编译器曾经遇到过函数 add
的定义(如果它先编译add.cpp 的话),但它并不会将其记下来。
编译器的这种短视和健忘是有意而为之的,这样可以确保具有相同名字的函数和变量不会发生冲突。我们会在下一节课中探讨命名冲突的问题。
解决的办法也是一样的:将 add
函数的定义移到 main
函数之前,或者使用前向声明。在本例中,由于 add
定义在其他文件中,因此调整定义顺序是不可以的。
因此使用前向声明才是更好的办法:
main.cpp (包含前向声明):
1 2 3 4 5 6 7 8 9 |
|
add.cpp (保持不变):
1 2 3 4 |
|
现在,当编译器编译 main.cpp 时,它会知晓标识符 add 。链接器则会将 main.cpp 文件中的 add
函数调用和 _add.cpp_中的函数定义关联起来。
使用该方法,我们就可以访问定义在其他文件中的函数了。
请自行使用前向声明并编译 add.cpp 和 main.cpp,如果你遇到了错误,请注意是否将 add.cpp 加入到了项目或编译命令中。
发生错误了!
在创建多文件程序时,可能会遇到很多不同错误。如果你尝试了上面的例子并遇到了一些错误,可以参考以下信息:
- 如果你遇到了
main
中没有定义add
的问题,和可能是因为忘记在 main.cpp 中对add
函数进行前向声明。 - 如果链接器报告了无法找到 add 定义的问题,例如:
1
unresolved external symbol "int __cdecl add(int,int)" (?add@@YAHHH@Z) referenced in function _main
- 最大的可能性是 add.cpp 文件没有被正确地添加到项目中。在编译程序的时候,你应该能够看到编译器列出了 main.cpp 和 add.cpp。如果你值看到了 main.cpp,那么 add.cpp 肯定没有被编译。如果你使用 Visual Studio 或 Code:: Blocks,你应该能够在 Solution Explorer/project 中看到 add.cpp。如果你没有看到,请右键点击项目并添加文件,然后尝试重新编译。如果你使用的是命令行的方式,请将 main.cpp 和 add.cpp 都包含在编译命令中。
- 你是不是将_add.cpp_ 添加到了错误的项目中?
- 也有可能是该文件被设置为不编译链接。请检查文件属性并确保将其配置为编译/链接。在 Code:: Blocks 中,编译和链接在两个单独的选择框中,请确保它们都被选中了。对于 Visual Studio 来说,请确保 “exclude from build” 选项被设置为 no 或空白。
- 不要在main.cpp中 #include “add.cpp”。这么做会导致编译器将 add.cpp 文件的内容直接插入 main.cpp 而不是将其当做单独的文件。
小结
当编译器在编译多文件程序时,它可能会以任意顺序来编译各个文件。不仅如此,编译器对个文件的编译还是独立的,它在编译某文件是不具备任何其他文件的信息。
在学习到面向对象编程后,我们会大量使用多文件构建程序,所以你从现在就应该好好掌握这种方式。
提醒一下:任何新创建的代码文件都应该被加入到项目中,这样它才会被编译。