关于C ++中头文件的简单问题

时间:2011-07-29 02:51:39

标签: c++ prototype header

假设我有3个文件:add.h,add.cpp和main.cpp。这是C ++培训站点上的一个常见示例,其中add.h包含名为“add”的函数的原型。 Add.cpp包含原型的声明,main.cpp包含add.h,然后调用add()函数将两个数字(x和y)一起添加。

我的问题是:无论我将add.cpp命名为什么,我的程序都运行得很好。 Elephant.cpp与doctorWhoRules.cpp一样有效。编译器是否搜索所有本地.cpp文件以在add.h中查找给定的原型?我没有在任何地方声明包含它的.cpp文件的名称。我只是对这是如何工作感到困惑。

谢谢!

6 个答案:

答案 0 :(得分:2)

我认为您正在混合JavaC++。在Java(像Eclipse这样的编辑器)中,存在一个通用限制,即您的class名称应与文件名相同。即。

// Add.java
class Add
{
}

在C ++中没有这样的限制。您的文件名可以是任何有意义的名称。您唯一需要注意的是您的实施文件包含.cpp / .cxx / .C等扩展名(我不知道现代编译器是否支持除此之外)

即使你的头文件也可以是除.cpp以外的任何其他任意扩展名;头文件的更常规扩展是.h.hpp等。

答案 1 :(得分:2)

名称是惯例。你可以任意命名,包括“weekly.newsletter”。您不必使用“add.cpp”。

也就是说,遵循惯例是明智的,除非你有理由不这样做,而且有些工具会使用扩展来推断使用的语言。

例如,当人们使用“foo.cpp”文件时,非常会让人感到困惑,就好像它们是头文件一样!然而,这在C ++中是允许的。然而,它违反惯例,编程很难实现。

答案 2 :(得分:1)

请参阅上面的文件名解答。链接器收集目标文件,匹配代码等并构建可执行文件。

答案 3 :(得分:1)

不同的可能性;

1)你实际上并没有重命名文件,你只是用一个新名称保存文件 - 而旧的add.cpp仍然存在并且仍然有效。

2)有一个旧的add.obj,它正在被链接

3)文件作为项目打开,visual-studio发现打开的文件实际上是你要编译成的文件和exe

答案 4 :(得分:1)

是的,编译器会搜索所有文件。更确切地说,它执行一次传递(“编译”),将代码减少到机器指令,并向每个文件添加它全局定义的符号列表(函数和变量名称),然后是第二次传递(“链接”,技术上不是完全匹配这些名称的部分编译器。

.h文件中原型的要点只是让编译器在编译main.cpp时可以使用add.cpp中实际定义的确切类型和名称(或者你称之为的任何内容)。这使得可以在不实际看到实现文件的情况下进行编译部分。

模板打破了这个“单独的编译”模型,因为编译器需要在编译期间看到模板的整个定义,因为它必须根据模板的方式生成特定于类的代码叫做。通常,模板放在.h文件中并包含在任何地方。

答案 5 :(得分:0)

假设我们有add.h add.cpp和main.cpp。

你需要main.cpp和add.cpp中的add原型。 main.cpp需要它,因为它想要使用类add和add.cpp需要它,因为它想要实现它,因此需要它的原型。如您所知,通过包含头文件来完成此操作。 在add.cpp和main.cpp中执行#include“add.h”。

现在编译器开始行动创建两个目标文件,即main.o和add.o.所以仍然主要只知道添加,内部机制(实现)仍然不存在。之后,链接器将main.o和add.o组合成一个可执行文件,其中包含运行从main添加的所有铃声和口哨声。

编译后,每个目标文件都按名称知道。在链接之后,他们实际上知道如何通过名称来调用它们(他(实现)所在的地方。

在编译器之前,我们有另一个称为预处理的步骤。在此步骤中完成的一件事是复制#include之后的文件内容。

无论你如何调用add.h都没关系,但你必须在main.cpp和add.cpp中包含正确的文件。无论你如何调用add.cpp或main.cpp,都只需要指示你的编译器如何调用它们。例如,在visual studio中,这是通过在项目文件中重命名它们自动完成的。如果使用gcc,您必须自己指导编译器和链接器。在这种特定情况下,您可以执行以下操作。

将add.cpp编译成add.o:

gcc -c add.cpp

将main.cpp编译为main.cpp:

gcc -c main.cpp

将add.o和main.o链接到myniceprogram:

gcc -o myniceprogram add.o main.o