What are forward declarations in C++?

Solution 1:

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.

Solution 2:

The compiler looks for each symbol being used in the current translation unit is previously declared or not in the current unit. It is just a matter of style providing all method signatures at the beginning of a source file while definitions are provided later. The significant use of it is when you use a pointer to a class as member variable of another class.

//foo.h
class bar;    // This is useful
class foo
{
    bar* obj; // Pointer or even a reference.
};

// foo.cpp
#include "bar.h"
#include "foo.h"

So, use forward-declarations in classes when ever possible. If your program just has functions( with ho header files), then providing prototypes at the beginning is just a matter of style. This would be anyhow the case had if the header file was present in a normal program with header that has only functions.

Solution 3:

Because C++ is parsed from the top down, the compiler needs to know about things before they are used. So, when you reference:

int add( int x, int y )

in the main function the compiler needs to know it exists. To prove this try moving it to below the main function and you'll get a compiler error.

So a 'Forward Declaration' is just what it says on the tin. It's declaring something in advance of its use.

Generally you would include forward declarations in a header file and then include that header file in the same way that iostream is included.

Solution 4:

The term "forward declaration" in C++ is mostly only used for class declarations. See (the end of) this answer for why a "forward declaration" of a class really is just a simple class declaration with a fancy name.

In other words, the "forward" just adds ballast to the term, as any declaration can be seen as being forward in so far as it declares some identifier before it is used.

(As to what is a declaration as opposed to a definition, again see What is the difference between a definition and a declaration?)

Solution 5:

When the compiler sees add(3, 4) it needs to know what that means. With the forward declaration you basically tell the compiler that add is a function that takes two ints and returns an int. This is important information for the compiler becaus it needs to put 4 and 5 in the correct representation onto the stack and needs to know what type the thing returned by add is.

At that time, the compiler is not worried about the actual implementation of add, ie where it is (or if there is even one) and if it compiles. That comes into view later, after compiling the source files when the linker is invoked.