Thursday, August 04, 2011

1.7 — Forward declarations « Learn C++

1.7 — Forward declarations « Learn C++


« 1.6 — Whitespace and basic formatting 1.8 — Programs with multiple files »



1.7 — Forward declarations
BY ALEX, ON JUNE 2ND, 2007
Take a look at this seemingly innocent sample program called add.cpp:

01
#include
02

03
int main()
04
{
05
using namespace std;
06
cout << "The sum of 3 and 4 is: " << add(3, 4) << endl;
07
return 0;
08
}
09

10
int add(int x, int y)
11
{
12
return x + y;
13
}
You would expect this program to produce the result:

The sum of 3 and 4 is: 7
But in fact, it doesn’t compile at all! Visual Studio 2005 Express produces the following compile errors:

add.cpp(10) : error C3861: 'add': identifier not found
add.cpp(15) : error C2365: 'add' : redefinition; previous definition was 'formerly unknown identifier'
The reason this program doesn’t compile is because the compiler reads files sequentially. When it reaches the function call to add() inside of main(), it doesn’t know what add is, because we haven’t defined add() until later! That produces the error on line 10. Then when it gets to the actual declaration of add(), it complains about add being redefined (which seems slightly misleading, given that it wasn’t ever defined in the first place). Often times, a single error in your code will end up producing multiple warnings.

Rule: When addressing compile errors in your programs, always resolve the first error produced first.

In this case, that means we need to address the fact that the compiler doesn’t know what add is. There are three ways to fix this problem.

The first way is to reorder our function calls so add is defined before main:

01
#include
02

03
int add(int x, int y)
04
{
05
return x + y;
06
}
07

08
int main()
09
{
10
using namespace std;
11
cout << "The sum of 3 and 4 is: " << add(3, 4) << endl;
12
return 0;
13
}
That way, by the time main() calls add(), it will already know what add is. Because this is such a simple program, this change is relatively easy to do. However, in a large program, it would be extremely tedious trying to decipher which functions called which other functions so they could be declared in the correct order.

Furthermore, this option is not always available. Let’s say we’re writing a program that has two functions A and B. If function A calls function B, and function B calls function A, then there’s no way to order the functions in a way that they will both be happy. If you define A first, the compiler will complain it doesn’t know what B is. If you define B first, the compiler will complain that it doesn’t know what A is.

Consequently, a better solution is to use a forward declaration. In a forward declaration, we declare (but do not define) our function in advance of where we use it, typically at the top of the file. This way, the compiler will understand what our function looks like when it encounters a call to it later. We do this by writing a declaration statement known as a function prototype. A function prototype is a declaration of a function that includes the function’s name, parameters, and return type, but does not implement the function.