C++ Language Tutorial

Forward Declarations | C++ Language Tutorial

In this lesson we will talk about forward declarations, which will help you understand how is actually a function called, what happens with the compiler when it encounters a function call and what it needs to know to compile the program.

Forward declaration

If you take a look at the examples we have used until now when talking about functions, you will notice one thing about their declaration and definition: we have always declared and defined our functions at the beginning of our source file, before the function main. In short terms, we have always declared and defined functions before calling them.

In order to see the difference and understand how our programs and compilers work, take one of the examples with functions, and move the function declaration and definition after the main function, therefore after the point we are actually calling and using that particular function. Now try to compile the program. It seems that it cannot be compiled, is it? Depending on the compiler you are using, you will get an error message, something along the lines of:

Use of undeclared identifier '<function_name>'

The reason why you are getting this compiler error is simple: in order to call a function, you must always declare it some point earlier, just like we did with every function example until now. This is because the compiler reads the source files sequentially, and when it reaches to our function call, it actually does not know anything about that identifier, what it is, or anything else, and that is why it is complaining.

Luckily, there is an alternative to writing the whole function definition prior to the point of calling it. We can achieve this by first declaring the functions that are to be used in our program, before any of their calls, and define them somewhere else, in the same source file, or another one, as we will soon see. But let’s stick first to just declaring them at the beginning of our main.cpp source file (or whatever name has your source file in your IDE), and then define them after the point where they are used. This way, you will better understand what exactly is going on and how the compilers work.

Let’s take a look and discuss the following example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//
//  main.cpp
//  ChapterII.ForwardDeclaration
//
//  Created by Vlad Isan on 20/04/2013.
//  Copyright (c) 2013 INNERBYTE SOLUTIONS LTD. All rights reserved.
//
 
#include <iostream>
 
using namespace std;
 
/*
 This is a forward declaration of our function add.
 This is called the function prototype.
 */
int add(int a, int b);
 
int main()
{
    cout << add(10, 15); /* Calling our function add. */
 
    return 0;
}
 
/*
 This is the point where we actually define our function.
 */
int add(int a, int b) {
    return (a + b);
}

As you can see in the example above we are first declaring our function add, calling it in main, and then writing the actual function’s body at the end of our source file. This way allows the compiler to understand how our function looks like, what is its return type, how many parameters are defined and their types, which are the only details it needs to know when encountering a call to it in our program. This is called a function prototype.

Now, when the compiler encounters a call to the function add, it already knows it is a function that returns an integer and has two integer parameters.

function prototype is just the functions‘s return type, its name and its parameters, without having to implement its body, the statements enclosed in braces ({ and }). This declaration always ends with a semicolon(;) as you can see in our example.

Another way to declare a function prototype is to omit the parameters’ names, thus our function declaration would look like:

int add(int, int);

One thing to point here is that, you should try to almost always include the parameters’ names into the function declaration as well, because you and others can easily understand what parameters the function has, which can make for a good description.

Another thing you can try is to remove the function definition from the source file and see what happens when you try to compile the program. In our example, when we are actually making a call to the add function, everything will compile just fine, but when the linker kicks in, it will complain about the missing function definition, because it cannot resolve the function call. You can get an “Unresolved symbol” error.

On the other hand, if you just declare and not define the function, but that function is never called, your code will compile and run just fine.

 

Leave a Reply