C++ 构建模型与 Java 模型完全不同。在 C++ 中,有各种实体的“声明”和“定义”,例如函数、类、方法等。C++ 源代码由一系列声明和定义组成。单个模块或“翻译单元”被编译成包含在该翻译单元中定义的任何实体的目标代码。然后,组成程序的编译翻译单元被“链接”在一起,其中一个翻译单元中定义的实体与它们在其他翻译单元中的用法相关联。
在翻译单元中,实体的某些使用只需要声明,而其他使用则需要完整的定义。例如,调用一个函数只需要声明该函数。创建一个指向对象的变量只需要声明对象的类型。创建一个类型是类类型(而不是指针)的变量需要类的完整定义。什么需要完整定义,什么只需要声明,取决于实现使用所需的内容。特别是如果使用只需要知道接口细节,那么声明就足够了,但是如果需要实现细节,那么就需要定义。
此外,指定 C++ 使得编译器几乎可以是单程的;声明和定义在使用之前必须出现在源代码中(大部分情况下;有一些例外),以便 C++ 在提及它时已经知道正在使用什么实体。
所以你的代码的问题是当编译器得到test()
它时不知道它是什么test
。它可以是类型、函数或变量。它不知道,因为它还没有被告知。你需要通过test
事先声明来告诉它。
void test();
int main() {
test();
}
现在编译器会在它尝试调用它时知道 test 是一个函数。而且由于调用函数不需要知道函数签名之外的任何内容,因此test
如果您愿意,可以将定义放入一个完全不同的翻译单元中。您将编译两个翻译单元,然后链接器会将调用该函数的代码连接test()
到另一个编译的翻译单元中的该函数的定义。
头文件是 C 和 C++ 中的一个常见技巧,它使在翻译单元之间共享声明的单一来源变得容易。它们不是绝对必要的,但是如果您通过在不同文件中声明稍有不同的内容来搞乱声明,那么您的程序可能会以意想不到和不可预测的方式失败。
#include
指令只需获取您命名的任何文件并将内容粘贴到您的源代码中。这样一来,无论您在标头中放置什么,例如函数声明,您都有一个单一的来源。这样,您可以确保在您需要的每个文件中都包含相同的声明,而不必担心您在一个文件中的声明是否与另一个文件略有不同。
您还可以将类定义放在头文件中,因为需要在以特定方式使用该类的每个翻译单元中重复类定义。同样,您可以在每个翻译单元中手动写出所需的信息,但将定义粘贴在标题中并让#include
指令为您完成复制和粘贴会更容易。
如果你想学习 C++,我建议你买一本好书。如果您还不熟悉编程,我会推荐Programming: Principles and Practice Using C++。既然你说你已经编程了,那么我听说对你来说更好的书可能是Accelerated C++。