什么是C ++中的前向声明? [英] What are forward declarations in C++?

查看:196
本文介绍了什么是C ++中的前向声明?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在: http://www.learncpp.com/cpp-tutorial / 19-header-files /

提到以下内容:

add.cpp:

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

main.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;
}




我们使用了前向声明,以便编译器会在编译 main.cpp 时知道 添加是什么。如前所述,为要在另一个文件中使用的每个函数编写前向声明会很快变得乏味。

We used a forward declaration so that the compiler would know what "add" was when compiling main.cpp. As previously mentioned, writing forward declarations for every function you want to use that lives in another file can get tedious quickly.

您能解释一下吗 转发声明还可以吗?如果在 main()函数中使用它,会出现什么问题?

Can you explain "forward declaration" further? What is the problem if we use it in the main() function?

推荐答案

为什么在C ++中需要向前声明

编译器希望确保您没有拼写错误或传递错误的数字该函数的参数。因此,它坚持认为,在使用 add(或任何其他类型,类或函数)之前,首先要看到一个声明。

The compiler wants to ensure you haven't made spelling mistakes or passed the wrong number of arguments to the function. So, it insists that it first sees a declaration of 'add' (or any other types, classes or functions) before it is used.

这实际上只是允许编译器以便更好地验证代码,并允许它整理松散的末端,以便生成美观的目标文件。如果您不必转发声明的内容,则编译器将生成一个目标文件,该文件必须包含有关添加功能可能是什么的所有可能猜测的信息。链接器必须包含非常聪明的逻辑,以尝试计算出您实际要调用的添加,当添加功能可能存在于不同的目标文件中时,链接器将与使用添加来生成的链接在一起dll或exe。链接器可能添加了错误的地址。假设您想使用int add(int a,float b),但偶然忘记了编写它,但是链接器发现一个已经存在的int add(int a,int b)并认为这是正确的方法,而是使用了它。您的代码可以编译,但不会达到您的期望。

This really just allows the compiler to do a better job of validating the code, and allows it to tidy up loose ends so it can produce a neat looking object file. If you didn't have to forward declare things, the compiler would produce an object file that would have to contain information about all the possible guesses as to what the function 'add' might be. And the linker would have to contain very clever logic to try and work out which 'add' you actually intended to call, when the 'add' function may live in a different object file the linker is joining with the one that uses add to produce a dll or exe. It's possible that the linker may get the wrong add. Say you wanted to use int add(int a, float b), but accidentally forgot to write it, but the linker found an already existing int add(int a, int b) and thought that was the right one and used that instead. Your code would compile, but wouldn't be doing what you expected.

因此,为了使内容保持明确并避免猜测,编译器坚持要求您在声明所有内容之前

So, just to keep things explicit and avoid the guessing etc, the compiler insists you declare everything before it is used.

声明和定义之间的区别

重要的是要知道声明和定义之间的区别。声明仅提供足够的代码来显示外观,因此对于函数而言,这是返回类型,调用约定,方法名称,参数及其类型。但是该方法的代码不是必需的。对于定义,您需要声明,然后还需要函数的代码。

As an aside, it's important to know the difference between a declaration and a definition. A declaration just gives enough code to show what something looks like, so for a function, this is the return type, calling convention, method name, arguments and their types. But the code for the method isn't required. For a definition, you need the declaration and then also the code for the function too.

前向声明如何显着减少构建时间

您可以通过#includ'已经包含该函数声明的标头,将函数的声明放入当前的.cpp或.h文件中。但是,这可能会减慢编译速度,尤其是在将#header包含在程序的.h而不是.cpp文件中的情况下,因为#include您正在编写的.h的所有内容最终都会#include's所有标题您也写了#includes。突然,即使您只想使用一个或两个函数,编译器也会包含#include页和需要编译的代码页。为避免这种情况,您可以使用前向声明,而您自己可以在文件顶部键入函数的声明。如果您仅使用一些函数,则与始终#include标头相比,这确实可以使您的编译更快。对于非常大的项目,差异可能是一个小时或更长时间的编译时间花费了几分钟。

You can get the declaration of a function into your current .cpp or .h file by #includ'ing the header that already contains a declaration of the function. However, this can slow down your compile, especially if you #include a header into a .h instead of .cpp of your program, as everything that #includes the .h you're writing would end up #include'ing all the headers you wrote #includes for too. Suddenly, the compiler has #included pages and pages of code that it needs to compile even when you only wanted to use one or two functions. To avoid this, you can use a forward-declaration and just type the declaration of the function yourself at the top of the file. If you're only using a few functions, this can really make your compiles quicker compared to always #including the header. For really large projects, the difference could be an hour or more of compile time bought down to a few minutes.

中断循环引用,其中两个定义都使用其他

此外,前向声明可以帮助您打破循环。这是两个函数都试图互相使用的地方。发生这种情况时(这是完全正确的做法),您可以#include一个头文件,但是该头文件试图#include您当前正在编写的头文件....然后#include其他头文件,其中#包括您要编写的内容。您陷入困境,每个头文件都试图重新#include另一个。要解决此问题,您可以在其中一个文件中预先声明所需的零件,并将#include保留在该文件之外。

Additionally, forward-declarations can help you break cycles. This is where two functions both try to use each other. When this happens (and it is a perfectly valid thing to do), you may #include one header file, but that header file tries to #include the header file you're currently writing.... which then #includes the other header, which #includes the one you're writing. You're stuck in a chicken and egg situation with each header file trying to re #include the other. To solve this, you can forward-declare the parts you need in one of the files and leave the #include out of that file.

例如:

文件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

Hmm ...这里需要Car的声明,因为Wheel有一个指向Car的指针,但是这里不能包含Car.h,因为这会导致编译器错误。如果包含Car.h,则将尝试包含Wheel.h,其中将包含Car.h,其中将包含Wheel.h,并且此操作将永远持续下去,因此编译器将引发错误。解决方案是改为转发声明Car:

Hmm... the declaration of Car is required here as Wheel has a pointer to a Car, but Car.h can't be included here as it would result in a compiler error. If Car.h was included, that would then try to include Wheel.h which would include Car.h which would include Wheel.h and this would go on forever, so instead the compiler raises an error. The solution is to forward declare Car instead:

class Car;     // forward declaration

class Wheel
{
    Car* car;
};

如果类Wheel具有需要调用car方法的方法,则可以在Wheel中定义这些方法。 cpp和Wheel.cpp现在可以包含Car.h而不会引起循环。

If class Wheel had methods which need to call methods of car, those methods could be defined in Wheel.cpp and Wheel.cpp is now able to include Car.h without causing a cycle.

这篇关于什么是C ++中的前向声明?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆