为什么在C ++中必须进行前向声明
编译器希望确保您没有犯拼写错误或没有将错误数量的参数传递给函数。因此,它坚持认为在使用“ add”(或任何其他类型,类或函数)之前,首先要看到一个声明。
这确实使编译器可以更好地验证代码,并整理松散的末端,从而可以生成外观整洁的目标文件。如果您不必转发声明的内容,则编译器将生成一个目标文件,该文件必须包含有关“添加”功能可能是什么的所有可能猜测的信息。链接器必须包含非常聪明的逻辑,才能尝试计算出您实际要调用的“添加”,当“添加”功能可能存在于不同的目标文件中时,链接器将与使用添加来生成的链接在一起dll或exe。链接器可能会添加错误的地址。假设您想使用int add(int a,float b),但无意间忘了编写它,但是链接器发现一个已经存在的int add(int a,诠释b)并认为这是正确的选择,而是改用了。您的代码可以编译,但是不会按预期执行。
因此,只是为了使事情保持明确,避免猜测,编译器坚持要求您在使用之前声明所有内容。
声明和定义之间的区别
顺便说一句,知道声明和定义之间的区别很重要。声明仅提供了足够的代码来显示外观,因此对于函数而言,这是返回类型,调用约定,方法名称,参数及其类型。但是该方法的代码不是必需的。对于定义,您需要声明,然后还需要函数的代码。
前向声明如何显着减少构建时间
您可以通过#includ包含已经包含该函数声明的标头,将函数的声明放入当前的.cpp或.h文件中。但是,这可能会减慢编译速度,尤其是在将#header包含在程序的.h而不是.cpp文件中的情况下,因为所有包含#h的内容都将最终包含在所有头文件中。您也为此写了#includes。突然,即使您只想使用一个或两个函数,编译器也会包含#include页和需要编译的代码页。为避免这种情况,您可以使用前向声明,而您自己可以在文件顶部键入函数的声明。如果只使用一些函数,则与始终包含头文件相比,这确实可以使编译更快。对于大型项目,
打破两个定义相互使用的循环引用
此外,前向声明可以帮助您打破循环。这是两个函数都试图互相使用的地方。发生这种情况时(这是完全正确的做法),您可以#include一个头文件,但是该头文件试图#include您当前正在编写的头文件....然后#include其他头文件,其中#包括您要编写的内容。您陷入困境,每个头文件都试图重新#include另一个。要解决此问题,您可以在其中一个文件中预先声明所需的零件,并将#include保留在该文件之外。
例如:
文件Car.h
#include "Wheel.h" // Include Wheel's definition so it can be used in Car.
#include <vector>
class Car
{
std::vector<Wheel> wheels;
};
文件Wheel.h
嗯...这里需要Car的声明,因为Wheel有一个指向Car的指针,但是这里不能包含Car.h,因为这会导致编译器错误。如果包含Car.h,则将尝试包含Wheel.h,其中将包含Car.h,其中将包含Wheel.h,并且此操作将永远持续下去,因此编译器将引发错误。解决的方法是转发声明Car代替:
class Car; // forward declaration
class Wheel
{
Car* car;
};
如果Wheel类中的方法需要调用car方法,则可以在Wheel.cpp中定义这些方法,而Wheel.cpp现在可以包含Car.h而不会引起循环。