C++多文件程序开发

将文件添加到您的项目中

随着程序的增大,为了组织或重用的目的,将它们分割成多个文件是很常见的做法。使用IDE(集成开发环境)的一个优势是它们使得处理多个文件变得更加容易。您已经知道如何创建和编译单文件项目。向现有项目添加新文件非常简单。

最佳实践 当您向项目添加新的代码文件时,请给它们一个.cpp扩展名。

在不同IDE中添加文件的方法

对于Visual Studio用户

在Visual Studio中,右键点击解决方案资源管理器窗口中的源文件文件夹(或项目名称),选择"添加">“新建项”……

vs

确保您选择了C++文件(.cpp)。给新文件一个名称,它将被添加到您的项目中。 注意:您的Visual Studio可能会选择显示紧凑视图而不是上面显示的完整视图。您可以使用紧凑视图,或者点击"显示所有模板"以获得完整视图。

vs2

注意:如果您从文件菜单而不是从解决方案资源管理器中的项目创建新文件,新文件将不会自动添加到您的项目中。您需要手动将其添加到项目中。为此,右键点击解决方案资源管理器中的源文件,选择"添加">“现有项”,然后选择您的文件。 现在当您编译程序时,您应该看到编译器在编译时列出您的文件名称。

对于Code::Blocks用户

在Code::Blocks中,转到文件菜单并选择"新建">“文件…"。

code

在"从模板新建"对话框中,选择C/C++源代码并点击"继续”。

code2

此时,您可能会或不会看到一个欢迎使用C/C++源文件向导对话框。如果看到了,点击"下一步"。

code3

在向导的下一页中,选择"C++“并点击"下一步”。

code4

现在给新文件一个名称(不要忘记.cpp扩展名),并点击"全部"按钮以确保所有构建目标都被选中。最后,选择完成。

code5

现在当您编译程序时,您应该看到编译器在编译时列出您的文件名称。

对于gcc用户

从命令行,您可以使用您喜欢的编辑器自行创建额外的文件,并给它一个名称。当您编译程序时,您需要在编译行上包含所有相关的代码文件。例如:g++ main.cpp add.cpp -o main,其中main.cpp和add.cpp是您的代码文件的名称,main是输出文件的名称。

对于VS Code用户

要创建一个新文件,选择"视图">“资源管理器"从顶部导航打开资源管理器面板,然后点击项目名称右侧的新文件图标。或者,选择"文件”>“新文件"从顶部导航。然后给您的新文件一个名称(不要忘记.cpp扩展名)。如果文件出现在.vscode文件夹内,将其向上拖动一级到项目文件夹。 接下来打开tasks.json文件,并找到”${file}“这行。 您这里有两个选项:

如果您希望明确指定哪些文件被编译,用您希望编译的每个文件的名称替换”${file}",每个文件一行,像这样:

"main.cpp",
"add.cpp",

读者"geo"报告说,您可以通过将"${file}“替换为”${fileDirname}\**.cpp"(在Windows上)让VS Code自动编译目录中的所有.cpp文件。

读者"Orb"报告说"${fileDirname}/**.cpp"在Unix上有效。

多文件示例

之前课程我们看了一个无法编译的单文件程序:

#include <iostream>

int main()
{
    std::cout << "The sum of 3 and 4 is: " << add(3, 4) << '\n';
    return 0;
}

int add(int x, int y)
{
    return x + y;
}

当编译器到达main的第5行的函数调用add时,它不知道add是什么,因为我们直到第9行才定义add!我们的解决方案是要么重新排序函数(将add放在第一位),要么使用add的前向声明。

多文件程序的编译问题

现在让我们看看一个类似的多文件程序: add.cpp:

int add(int x, int y)
{
    return x + y;
}

main.cpp:

#include <iostream>

int main()
{
    std::cout << "The sum of 3 and 4 is: " << add(3, 4) << '\n'; // 编译错误
    return 0;
}

您的编译器可能会先编译add.cpp或main.cpp。无论如何,main.cpp将无法编译,给出与前一个示例相同的编译错误:

main.cpp(5) : error C3861: 'add': identifier not found

原因也完全相同:当编译器到达main.cpp的第5行时,它不知道标识符add是什么。

编译器的工作方式

记住,编译器单独编译每个文件。它不知道其他代码文件的内容,也不记住它从先前编译的代码文件中看到的内容。所以即使编译器之前可能已经看到了函数add的定义(如果它先编译了add.cpp),它也不会记住。

这种有限的可见性和短暂的记忆是有意为之的,原因有几个:

  1. 它允许项目的源文件以任何顺序编译。
  2. 当我们更改源文件时,只需要重新编译该源文件。
  3. 它减少了不同文件中标识符之间的命名冲突的可能性。

我们将在下一课中探讨当名称确实发生冲突时会发生什么。

解决多文件程序中的编译问题

我们这里的解决方案与之前相同:将函数add的定义放在函数main之前,或用前向声明满足编译器。在这种情况下,因为函数add在另一个文件中,所以重新排序选项是不可能的。 解决方案是使用前向声明: main.cpp(带前向声明):

#include <iostream>

int add(int x, int y); // 需要这个,以便main.cpp知道add()是在其他地方定义的函数

int main()
{
    std::cout << "The sum of 3 and 4 is: " << add(3, 4) << '\n';
    return 0;
}

add.cpp(保持不变):

int add(int x, int y)
{
    return x + y;
}

现在,当编译器编译main.cpp时,它将知道标识符add是什么并感到满意。链接器将把main.cpp中的add函数调用连接到add.cpp中的add函数定义。 使用这种方法,我们可以给文件访问居住在另一个文件中的函数。

自己尝试编译

自己尝试编译带有前向声明的add.cpp和main.cpp。如果您遇到链接器错误,请确保您已正确地将add.cpp添加到您的项目或编译行中。

关于头文件包含的提示

提示 由于编译器单独编译每个代码文件(然后忘记它所看到的),每个使用std::cout或std::cin的代码文件都需要#include 。 在上面的例子中,如果add.cpp使用了std::cout或std::cin,它将需要#include

关键洞见

当一个标识符在表达式中被使用时,该标识符必须与其定义连接。

如果编译器在正在编译的文件中既没有看到前向声明也没有看到标识符的定义,它将在标识符被使用的地方报错。

否则,如果定义存在于同一文件中,编译器将把标识符的使用与其定义连接起来。

否则,如果定义存在于不同的文件中(并且对链接器可见),链接器将把标识符的使用与其定义连接起来。

否则,链接器将发出错误,表明它找不到标识符的定义。

常见问题及解决方案

出了点问题! 当您第一次尝试使用多个文件时,可能会有很多问题。如果您尝试上述示例并遇到错误,请检查以下内容:

编译器错误

如果您在main中得到一个编译器错误,说add没有被定义,您可能忘记了在main.cpp中为函数add添加前向声明。

链接器错误

如果您得到一个链接器错误,说add没有被定义,例如:

unresolved external symbol "int __cdecl add(int,int)" (?add@@YAHHH@Z) referenced in function _main

2a. ……最可能的原因是add.cpp没有正确添加到您的项目中。当您编译时,您应该看到编译器列出了main.cpp和add.cpp。如果您只看到main.cpp,那么add.cpp肯定没有被编译。如果您使用Visual Studio或Code::Blocks,您应该在IDE左侧或右侧的解决方案资源管理器/项目窗格中看到add.cpp。如果没有,右键点击您的项目,添加文件,然后再次尝试编译。如果您在命令行上编译,不要忘记在您的编译命令中包含main.cpp和add.cpp。

2b. ……可能是您将add.cpp添加到了错误的项目中。

2c. ……可能是文件设置为不编译或不链接。检查文件属性,确保文件配置为被编译/链接。在Code::Blocks中,编译和链接是应该被选中的单独复选框。在Visual Studio中,有一个"从构建中排除"选项,应该设置为"否"或留空。确保您分别检查每个构建配置(例如调试和发布)。

常见错误

不要从main.cpp中#include “add.cpp”。虽然这样做在这种情况下可以编译,#include .cpp文件会增加命名冲突和其他意外后果的风险(特别是随着程序变得更大更复杂)。

总结

C++的设计使得每个源文件可以独立编译,无需知道其他文件中的内容。因此,文件实际编译的顺序应该是不相关的。

一旦我们开始面向对象编程,我们将大量使用多个文件,所以现在是一个好时机,确保您了解如何添加和编译多个文件项目。 提醒:每当您创建一个新的代码(.cpp)文件时,您都需要将其添加到您的项目中,以便它被编译。

关注公众号,回复"cpp-tutorial"

可领取价值199元的C++学习资料

公众号二维码

扫描上方二维码或搜索"cpp-tutorial"