在: http: //www.learncpp.com/cpp-tutorial/19-header- files/
提到以下内容:
添加.cpp:
int add(int x, int y) { return x + y; }
主.cpp:
#include <iostream> int add(int x, int y); // forward declaration using function prototype int main() { using namespace std; cout << "The sum of 3 and 4 is " << add(3, 4) << endl; return 0; }
我们使用了前向声明,以便编译器在编译时知道“ add”是什么main.cpp。如前所述,为要使用的每个位于另一个文件中的函数编写前向声明会很快变得乏味。
add
main.cpp
你能进一步解释一下“ 前向声明 ”吗?如果我们在main()函数中使用它会出现什么问题?
main()
为什么在 C++ 中需要前向声明
编译器希望确保您没有犯拼写错误或将错误数量的参数传递给函数。因此,它坚持在使用它之前首先看到“add”(或任何其他类型、类或函数)的声明。
这实际上只是允许编译器更好地验证代码并允许它整理松散的末端,以便它可以生成一个看起来整洁的目标文件。如果您不必转发声明事物,编译器将生成一个目标文件,该文件必须包含有关函数add可能是什么的所有可能猜测的信息。并且链接器必须包含非常聪明的逻辑来尝试计算出add您实际打算调用的函数,当add函数可能存在于不同的目标文件中时,链接器将与使用 add 生成dllor的目标文件连接exe。链接器可能会出错add。假设你想使用int add(int a, float b),但不小心忘记写了,但链接器发现了一个已经存在的int add(int a, int b)并认为这是正确的,而是使用了它。您的代码会编译,但不会按照您的预期进行。
dll
exe
int add(int a, float b)
int add(int a, int b)
因此,为了保持明确并避免猜测等,编译器坚持要求您在使用之前声明所有内容。
声明与定义的区别
顺便说一句,了解声明和定义之间的区别很重要。声明只提供了足够的代码来显示某些东西的样子,因此对于函数,这是返回类型、调用约定、方法名称、参数及其类型。但是,不需要该方法的代码。对于定义,您需要声明,然后还需要函数的代码。
前向声明如何显着减少构建时间
您可以通过#includ’ing 已经包含函数声明的标头将函数声明放入当前文件.cpp或文件中。.h但是,这可能会减慢您的编译速度,特别是如果您#include将标头放入 a.h而不是.cpp您的程序,因为所有#includes.h你正在写的东西最终会#include’ing你写#includes的所有标题。突然间,编译器有#included 页面和需要编译的代码页面,即使您只想使用一两个函数也是如此。为避免这种情况,您可以使用前向声明并在文件顶部自己键入函数的声明。如果您只使用几个函数,与总是#include 标头相比,这确实可以使您的编译更快。对于非常大的项目,差异可能是一个小时或更长时间的编译时间缩短到几分钟。
.cpp
.h
#include
中断两个定义都相互使用的循环引用
此外,前向声明可以帮助您打破循环。这是两个函数都试图相互使用的地方。当这种情况发生时(这是一件完全有效的事情),您可能会使用#include一个头文件,但该头文件会尝试访问#include您当前正在编写的头文件......然后#includes另一个头文件,其中#includes你正在写的一个。您陷入了鸡与蛋的局面,每个头文件都试图重新#include 另一个。为了解决这个问题,您可以在其中一个文件中前向声明您需要的部分,并将#include 保留在该文件之外。
例如:
文件车.h
#include "Wheel.h" // Include Wheel's definition so it can be used in Car. #include <vector> class Car { std::vector<Wheel> wheels; };
文件轮.h
嗯…Car这里需要声明 of ,因为Wheel它有一个指向 a 的指针Car,但Car.h不能包含在这里,因为它会导致编译器错误。如果Car.h被包含,那么它将尝试包含Wheel.h哪些将包含Car.h哪些将包含Wheel.h并且这将永远持续下去,因此编译器会引发错误。解决方案是转发声明Car:
Car
Wheel
Car.h
Wheel.h
class Car; // forward declaration class Wheel { Car* car; };
如果类Wheel有方法需要调用 的方法Car,这些方法可以在中定义Wheel.cpp并且Wheel.cpp现在能够包含Car.h而不会导致循环。
Wheel.cpp