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

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

问题描述

在:http://www.learncpp.com/cpp-tutorial/19-头文件/

提到以下内容:

add.cpp:

int add(int x, int y){返回 x + y;}

main.cpp:

#include int add(int x, int y);//使用函数原型进行前向声明int main(){使用命名空间标准;cout<<3和4之和是"<<添加(3, 4)<<结束;返回0;}

<块引用>

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

您能否进一步解释前向声明"?如果我们在 main() 函数中使用它有什么问题?

解决方案

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

编译器希望确保您没有出现拼写错误或将错误数量的参数传递给函数.因此,它坚持在使用之前首先看到add"(或任何其他类型、类或函数)的声明.

这实际上只是允许编译器更好地验证代码并允许它整理松散的末端,以便它可以生成一个看起来整洁的目标文件.如果您不必转发声明内容,编译器将生成一个目标文件,该文件必须包含有关函数 add 可能是什么的所有可能猜测的信息.当 add 函数可能存在于链接器的不同目标文件中时,链接器必须包含非常聪明的逻辑来尝试确定您实际打算调用哪个 add正在加入使用 add 生成 dllexe 的那个.链接器可能会得到错误的add.假设你想使用int add(int a, float b),但是不小心忘记写了,但是链接器发现一个已经存在的int add(int a, int b)code> 并认为这是正确的并使用它.您的代码可以编译,但不会按照您的预期运行.

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

声明与定义的区别

顺便说一句,了解声明和定义之间的区别很重要.声明只是提供足够的代码来显示某些东西的样子,因此对于函数,这是返回类型、调用约定、方法名称、参数及其类型.但是,不需要该方法的代码.对于定义,您需要声明,然后还需要函数的代码.

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

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

打破循环引用,其中两个定义都互相使用

此外,前向声明可以帮助您打破循环.这是两个函数都试图相互使用的地方.当发生这种情况时(这是一件完全有效的事情),您可以 #include 一个头文件,但该头文件会尝试 #include 您的头文件正在写...然后#includes 另一个标题,其中#includes 你正在写的那个.您陷入了鸡与蛋的困境,每个头文件都试图重新#include 另一个.要解决此问题,您可以在其中一个文件中预先声明您需要的部分,并将 #include 保留在该文件之外.

例如:

文件 Car.h

#include "Wheel.h";//包含 Wheel 的定义,以便它可以在 Car 中使用.#include <向量>类车{std::vector轮子;};

文件 Wheel.h

嗯...这里需要声明Car,因为Wheel 有一个指向Car 的指针,但是Car.h 不能包含在这里,因为它会导致编译器错误.如果包含 Car.h,那么将尝试包含 Wheel.h 将包含 Car.h 将包含 Wheel.h 这将永远持续下去,因此编译器会引发错误.解决方案是转发声明Car:

class Car;//前向声明班轮{车*车;};

如果Wheel类有方法需要调用Car的方法,可以在Wheel.cpp中定义这些方法Wheel.cpp 现在可以包含 Car.h 而不会导致循环.

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

The following is mentioned:

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

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.

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

解决方案

Why forward-declare is necessary in C++

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.

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 guessing, etc, the compiler insists you declare everything before it is used.

Difference between declaration and definition

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. However, the code for the method isn't required. For a definition, you need the declaration and then also the code for the function too.

How forward-declarations can significantly reduce build times

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.

Break cyclic references where two definitions both use each other

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.

Eg:

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

File Wheel.h

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

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天全站免登陆