Search

2.7 — Forward declarations and definitions

Take a look at this seemingly innocent sample program:

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 produces the following compile error:

add.cpp(5) : error C3861: 'add': identifier not found

The reason this program doesn’t compile is because the compiler compiles the contents of code files sequentially. When the compiler reaches the function call to add on line 5 of main, it doesn’t know what add is, because we haven’t defined add until line 9! That produces the error, identifier not found.

Older versions of Visual Studio would produce an additional error:

add.cpp(9) : error C2365: 'add' : redefinition; previous definition was 'formerly unknown identifier'

This is somewhat misleading, given that add wasn’t ever defined in the first place. Despite the redundancy of the second error message, it’s useful to note that it is fairly common for a single error to produce (often redundant) multiple compiler errors or warnings.

Best practice

When addressing compile errors in your programs, always resolve the first error produced first and then compile again.

To fix this problem, we need to address the fact that the compiler doesn’t know what add is. There are two common ways to address the issue.

Option 1: Reorder the function calls

One way to address the issue is to reorder the function calls so add is defined before main:

That way, by the time main calls add, the compiler will already know what add is. Because this is such a simple program, this change is relatively easy to do. However, in a larger program, it can be tedious trying to figure out which functions call which other functions (and in what order) so they can be declared sequentially.

Furthermore, this option is not always possible. 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 will make the compiler 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.

Option 2: Use a forward declaration

We can also fix this by using a forward declaration.

A forward declaration allows us to tell the compiler about the existence of an identifier before actually defining the identifier.

In the case of functions, this allows us to tell the compiler about the existence of a function before we define the function’s body. This way, when the compiler encounters a call to the function, it’ll understand that we’re making a function call, and can check to ensure we’re calling the function correctly, even if it doesn’t yet know how or where the function is defined.

To write a forward declaration for a function, we use a declaration statement called a function prototype. The function prototype consists of the function’s return type, name, parameters, but no function body (the curly braces and everything in between them), terminated with a semicolon.

Here’s a function prototype for the add function:

Now, here’s our original program that didn’t compile, using a function prototype as a forward declaration for function add:

Now when the compiler reaches the call to add in main, it will know what add looks like (a function that takes two integer parameters and returns an integer), and it won’t complain.

It is worth noting that function prototypes do not need to specify the names of the parameters. In the above code, you can also forward declare your function like this:

However, we prefer to name our parameters (using the same names as the actual function), because it allows you to understand what the function parameters are just by looking at the prototype. Otherwise, you’ll have to locate the function definition.

Best practice

When defining function prototypes, keep the parameter names. You can easily create forward declarations by using copy/paste on your function declaration. Don’t forget the semicolon on the end.

Forgetting the function body

New programmers often wonder what happens if forward declare a function but do not define it.

The answer is: it depends. If a forward declaration is made, but the function is never called, the program will compile and run fine. However, if a forward declaration is made and the function is called, but the program never defines the function, the program will compile okay, but the linker will complain that it can’t resolve the function call.

Consider the following program:

In this program, we forward declare add, and we call add, but we never define add anywhere. When we try and compile this program, Visual Studio produces the following message:

Compiling...
add.cpp
Linking...
add.obj : error LNK2001: unresolved external symbol "int __cdecl add(int,int)" (?add@@YAHHH@Z)
add.exe : fatal error LNK1120: 1 unresolved externals

As you can see, the program compiled okay, but it failed at the link stage because int add(int, int) was never defined.

Other types of forward declarations

Forward declarations are most often used with functions. However, forward declarations can also be used with other identifiers in C++, such as variables and user-defined types. Variables and user-defined types have a different syntax for forward declaration, so we’ll cover these in future lessons.

Declarations vs. definitions

In C++, you’ll often hear the words “declaration” and “definition” used, often interchangeably. What do they mean? You now have enough of a framework to understand the difference between the two.

A definition actually implements (for functions or types) or instantiates (for variables) the identifier. Here are some examples of definitions:

A definition is needed to satisfy the linker. If you use an identifier without providing a definition, the linker will error.

The one definition rule (or ODR for short) is a well-known rule in C++. The ODR has three parts:

  1. Within a given file, a function, object, type, or template can only have one definition.
  2. Within a given program, an object or normal function can only have one definition. This distinction is made because programs can have more than one file (we’ll cover this in the next lesson).
  3. Within a given program, types, template functions, and inline functions can have multiple definitions so long as they are identical. We haven’t covered what most of these things are yet, so don’t worry about this for now -- we’ll bring it back up when it’s relevant.

Violating part 1 of the ODR will cause a compile to issue a redefinition error. Violating ODR parts 2 or 3 will cause the linker to issue a redefinition error. Here’s an example of a violation of part 1:

Because the above program violates ODR part 1, this causes the Visual Studio compiler to issue the following compile errors:

project3.cpp(9): error C2084: function 'int add(int,int)' already has a body
project3.cpp(3): note: see previous definition of 'add'
project3.cpp(16): error C2086: 'int x': redefinition
project3.cpp(15): note: see declaration of 'x'

A declaration is a statement that tells the compiler about the existence of an identifier and its type information. Here are some examples of declarations:

A declaration is all that is needed to satisfy the compiler. This is why we can use a forward declaration to tell the compiler about an identifier that isn’t actually defined until later.

In C++, all definitions also serve as declarations. This is why int x appears in our examples for both definitions and declarations. Since int x is a definition, it’s a declaration too. In most cases, a definition serves our purposes, as it satisfies both the compiler and linker. We only need to provide an explicit declaration when we want to use an identifier before it has been defined.

While it is true that all definitions are declarations, the converse is not true: all declarations are not definitions. An example of this is the function prototype -- it satisfies the compiler, but not the linker. These declarations that aren’t definitions are called pure declarations. Other types of pure declarations include forward declarations for variables and type declarations (you will encounter these in future lessons, no need to worry about them now).

The ODR doesn’t apply to pure declarations (it’s the one definition rule, not the one declaration rule), so you can have as many pure declarations for an identifier as you desire (although having more than one is redundant).

Author's note

In common language, the term “declaration” is typically used to mean “a pure declaration”, and “definition” is used to mean “a definition that also serves as a declaration”. Thus, we’d typically call int x; a definition, even though it both a definition and a declaration.

Quiz time

Question #1

What is a function prototype?

Show Solution

Question #2

What is a forward declaration?

Show Solution

Question #3

How do we declare a forward declaration for functions?

Show Solution

Question #4

Write the function prototype for this function (use the preferred form with names):

Show Solution

Question #5

For each of the following programs, state whether they fail to compile, fail to link, or compile and link. If you are not sure, try compiling them!

a)

Show Solution

b)

Show Solution

c)

Show Solution

d)

Show Solution


2.8 -- Programs with multiple code files
Index
2.6 -- Whitespace and basic formatting

118 comments to 2.7 — Forward declarations and definitions

  • Florian

    Ok,

    I was thinking about it for a second, here is my explanation maybe someone can tell me if i am right.

    The program does work because c++ is compiled rather than interpreted. Which means as soon as we have created a prototyp the compiler gets through until the end and the compiled program has overwriten the first Prototype with the completed declaration (since the later declaration supersedes the first statement?

    Florian

    • Eugene

      Not quite. The prototype does not get overwritten. Rather, the forward declaration informs the compiler of how a call of that function should look like, and thus the compiler can do the necessary setup and translate the function call into assembly/machine code.

      The function definition defines the code that will be executed when the function is called. In this case it is in the same source file as the function call, but it could be in a different source file, or might not even be available at all, e.g., just the object code is available in a shared library.

      That said, some functions whose function definitions are available might be inlined, i.e., the function call is replaced by the code of the function itself.

  • Florian

    Hi,
    i do have a problem understanding this:

    #include <iostream>
    
    int add(int x, int y); // forward declaration of add() using a function prototype
    
    int main()
    {
        using namespace std;
        cout << "The sum of 3 and 4 is: " << add(3, 4) << endl;
        return 0;
    }
    
    int add(int x, int y)
    {
        return x + y;
    }
    

    As the tutorial has stated earlier the program is running line by line so the function add would be unrecognized when it is called while add() is declared later on.

    On this example I would actually realize that we have created add() called it in main BUT we never reach the line where return x+y was written down.

    Basically I would expect a link error since the call ends up without returning anything?

    So my question is why does the program knows that add() returns the value x+y when it shouldn't reach that declaration?

    Hope someone can understand this, i am German my English certainly lacks a bit.

    Thanks
    Florian

  • Jon

    I don't know if this was mentioned yet, on a brief scan I didn't see it, so forgive me if you already answered this...
    You defined a function prototype as:

    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. In Question #2 on this page you give us:

    1.int DoMath(int first, int second, int third, int fourth)
    2.{
    3.     return first + second * third / fourth;
    4.}

    Did you mean us to solve for the forward declaration? If not, and you did mean to ask for the Function Prototype, shouldn't you have given us only the Forward Declaration?

  • Prayrit

    This is a weird concept to me, because every other language I've worked with(java, c#, actionscript) doesn't care where the function is located...

  • secure virginia slims ultra sunlight cigarettes
    second-rate doral cigarette cheaply doral cigarette|penurious doral cigarettes
    shoddy doral cigarettes cheap doral cigarettes
    inferior gpc cigarette tuppenny gpc cigarettes
    tuppenny gpc cigarettes cheap gpc cigarettes
    discount doral cigarettes

  • Danny
    #include "stdafx.h
    #include    
      
    int add(int 1, int 2, int 3, int 4);    
      
    int main()   
    {   
        using namespace std;   
        cout << "The sum of first, second, third, and forth =" << add(1,2,3,4) << endl;   
        return 0;   
    }   
      
    int add(int 1, int 2, int 3, int 4);    
    {   
         return 1 + 2 + 3 + 4;   
    } 
    

    Y doesn't it work? =/ can someone please help

    • Furious Sideburns

      I'll have a crack at answering this (I'm new to all this myself). If I'm understanding this right, you've got a few syntax errors.

      You're missing a " at the end of your first #include

      #include "stdafx.h

      should be

      #include "stdafx.h"

      Also, you need to lose the ; on the end of your forward declaration and your add function

      int add(int 1, int 2, int 3, int 4);

      and

      int add(int 1, int 2, int 3int 4);

      should be

      int add(int 1, int 2, int 3, int 4)

      and

      int add(int 1, int , int 3, int 4)
      • csvan

        You almost got it, however you NEED to have a ; at the end of forware declarations, since they are statements. Thus, it is compleely correct to write:

        int add(int a, int b);

        but not without the semicolon. C++ statements are ALWAYS concluded with semicolon (except for some structures, such as while and for loops).

        Also, you CANNOT write a parameters name as a number (for example int add(int 1);), that is not allowed by the compiler.

        Keep on coding. Use it for good. :)

    • csvan

      You have 3 errors here:

      1. The first line is missing a closing quotation mark (") at the end (it should be "stdafx.h").

      2. The second include statement does not include anything. I think you meant to include iostream, therefore it should read:

      #include <iostream> 

      3. The name of a parameter (or any variable as far as I know) can never start with a number, or simply be a number. Therefore, you will have to rename the parameters both in the function prototype and definition for add, for example like this:

      int add(int a, int b, int c, int 4);
        

      and make the same changes to the body of the function (change 1 to a etc).

      Keep coding. Use it for good.

  • Justin

    Hi i have a question... i wrote my own code (same as yours but didn't copy and paste) and i got a weird error that i do not under stand here is my code

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

    int main()
    {
    using namespace std;
    cout << "the sum of 3+4 is : " << add(3, 4)<< endl;
    system ("pause");
    return 0;
    }

    and this is the error message: 3 D:Dev-Cppmain.cpp expected `,' or `;' before '{' token

    Thankz
    Justin

  • i m very weak in programing how can i improve it

    • Practice makes perfect! Pick a small project and figure out how to code it. Eg. a calculator, an address book, a little game, etc... You will learn as much from working on your own code and solving the problems you run into as you will from these tutorials.

      • csvan

        I double that. And triple it. I believe practical work is absolutely essential to building solid programming competence. You can learn all your life, but learning is in vain if it is only forgotten. Putting learnt knowledge into practice helps solidify it, and, I believe, can really contribute to it becoming a permanent part of your routine, not easily forgotten.

  • Julian

    I just found this site today after frustratingly leaving a different "learn C++" website, and I must say, your tutorials are a 100 times better than the other site I was on! :P

    It had about one paragraph on functions which was badly worded, and then went on to something about arrays and loops and binary trees and it had examples but they used functions in a way I didn't even know was possible and it just confused the crackers outta me.

    I like the way these tutorials don't teach everything about 'functions' in the one chapter, they teach the aspects of functions that would be easy to understand at this point, and then explain the more advanced features when the reader has a bit more knowledge about C++.

    Thankyou! :D

  • peddi

    Can we say the forward declaration in nothing but declaring the function globally, where as function prototyping is declaring function locally i.e, in the main function? is that only the difference? If then there is no way we can block the outsider from accessing our function which declared using forward declaration?

    • A forward declaration is a specific type of function prototype that allows you to declare a function before you actually define it. Unfortunately, there's no way to "hide" such functions from "outsiders" -- even if you don't declare a function prototype, someone who wanted to use your function could write a function prototype for it and then use it.

      The only way to hide functions is to put them inside classes, which we'll cover much later in this tutorial.

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">