2.6 — 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 this, it’s useful to generally note that it is fairly common for a single error to produce many redundant or related 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 definitions

One way to address the issue is to reorder the function definitions 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 they 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:

add.obj : error LNK2001: unresolved external symbol "int __cdecl add(int,int)" ([email protected]@[email protected])
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. Types, templates, inline functions, and variables are allowed to have identical definitions in different files. 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 the compiler to issue a redefinition error. Violating ODR part 2 will likely cause the linker to issue a redefinition error. Violating ODR part 3 will cause undefined behavior.

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'

For advanced readers

Functions that share an identifier but have different parameters are considered to be distinct functions. We discuss this further in lesson 8.9 -- Introduction to function overloading

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 is 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, fail both, or compile and link successfully. If you are not sure, try compiling them!


Show Solution


Show Solution


Show Solution


Show Solution

2.7 -- Programs with multiple code files
2.5 -- Why functions are useful, and how to use them effectively

328 comments to 2.6 — Forward declarations and definitions

  • Waldo Lemmer

    Section "Declarations vs. definitions":

    Error output:


    The line numbers don't match the code, FTFY:

  • Nenad

    What is the benefit of function declarations? Why wouldn't I just define the function right away if I know what it should do? I understand how this works, just looking for a practical example of when it would be better to declare a function first and define it later vs. doing both the declaration and definition at the same time? Thanks!

    • Alex

      Once you get into programs that use multiple files, declarations (in header files) are used all the time. You'll run into that topic later in this chapter.

  • Suresh R

    Dear Sir,

    Thank you for this nice tutorial as I don't have any basic knowledge on this subject. But I am learning each chapter in the given order.

    My query is what is the advantage of the function prototype while comparing with normal functions? I tried both options and it takes lesser time for normal function than function prototype.

    • Zheng Wei

      Function prototypes are useful for forward declarations which "allows us to tell the compiler about the existence of an identifier before actually defining the identifier." As far as I know there are 2 important reasons for this:
      1. As mentioned in the tutorial:
      "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." - so in this case a forward declaration is necessary.

      2. To make the code more readable as if all functions were placed above the main() function, the programmer would have to scroll all the way to the bottom of the file just to see the main() function.

  • Michael Adeleye

    I like the approach of this C++ tutorial's website.
    These lessons are not as boring to me as my previous experiences with C++. (I've been learning C++ on my own since 2002 and I can rate myself only 45%).

    Thanks to the instructors for their regular updates and those who offer good comments.
    I'm learning as a hobby, my field is Electrical but I know no knowledge will be lost on the long run.

    I'm sure when I fully understand POINTERS and GUI, I can rate myself 70%(as with my experience in PYTHON).
    I'm modifing the codes in the tutorial and I'm enjoying myself up till now.


  • J34NP3T3R

    why cant C++ just read through the rest of the project codes first
    then identify the functions
    and automatically create forward declaration for each functions ?

    • Morningfrost

      I think it's for the same reason C can't. When the language was defined, compiling time was a significant issue, and reading the source twice was not an option.

      Also, forward declarations can be in a separate header file (.h) and the program itself can be made of more than one source file.

    • Swiss

      Why not make such a language yourself.
      Not criticizing but necessity is mother of all creation.:)

  • qwerty

    When does the execution stop here?

  • Euphoria

    I had a bit of a hard time understanding definition and declaration when it came to variables, such as int x, and have a possible clarification I would like to suggest!

    When it comes to a function prototype, I did not understand why it was that it remained uninstantiated whilst int x would be instantiated when it is technically holding 'no value', the same as the function prototype.

    Adding a clarification in that a function does not hold a value in itself but is a piece used for computation, whilst an uninitialized variable such as int x still holds an indeterminate value could help show why int x is both a definition and declaration, while a function prototype is just a declaration as it wouldn't make sense to instantiate something holding no value.

  • Euphoria

    "Types, templates, and inline functions and variables are allowed to have identical definitions in different files."

    Minor typo!
    "Types, templates, (remove and) inline functions and variables"

  • Noah Dugan

    Hey guys, sorry for this super basic question, but for question c, why does this compile?

    I understand how it clearly won’t link because the linker which tries to resolve the call to add() can’t find an add() with two parameters. But why isn’t there a compilation issue, given that the function add() was declared with 2 parameters and then defined with 3 parameters. I guess in a more basic way, and sorry if this has been covered - since you can declare something multiple times, and all definitions are also declarations, the parametrization of two declarations for any given function can be different and yet still compile?

    Another example would be if I forward declared doSomething() with no parameters and then later on defined it with several int parameters. I thought the compiler would not accept the conflicting declarations. What am I missing here?

    Thanks for all of this by the way. The pandemic has brought me here and this site has brought me and I’m sure many others a lot of joy!

    • nascardriver

      Functions can be overloaded. Overloading means there are multiple functions with the same name, but different parameters. This allows things like

      Function overloading is covered later.

  • In the case of primitive/builtin types, the only declaration which doesnt include definition is whrn you declare a global variable with the extern keyword?

  • Just to clarify, is the static member definition the only case (in the case of variables, not functions) which doesnt mean declaration as well?

  • Function prototype, declararion and signature are the same things?

    • nascardriver

      Prototype and declaration yes. Signature no.
      The function signature sums up certain properties of a function, most importantly its name and parameters. The function signature is used to check if 2 functions are the same and to look up a function based on a function call.

  • Jim177

    Is it safe to say that if you declare a function before main, that you never need a semicolon after the name and it parameters? int add(int x, int y)

    However if you forward declare that same function then you need to add the semicolon?  But then the function itself shown after the main function need no semicolon?
    #include <iostream>

    int add(int x, int y);
    int main()
        std::cout << "The sum of 3 and 4 is: " << add(3, 4) << '\n';
        return 0;
    int add(int x, int y)
        return x + y;

    If the above is all true than this should be a rule or best practice.  Can we also say that every function must have at least one parameter and this parameter can not be nill or 0?

    • nascardriver

      A declaration needs a semicolon, a definition does not. The lesson already says the a forward declaration is terminated by a semicolon.
      Not all functions have parameters, for example your `main()` function.

  • Thomas Ødum Wiggers

    From 1.3 - Introduction to variables:
    "In order to create a variable, we use a special kind of declaration statement called a definition (we’ll
    clarify the difference between a declaration and definition later).

    Here’s an example of defining a variable named x:


    However, here you tell us that this is only a declaration, and since that it hasn't been assigned a value, then it hasn't been instantiated. I don't get it. Please help. Thank you :)

    • nascardriver

      instantiates an `int`, it's a definition and a declaration.

      "In C++, all definitions also serve as declarations. This is why int x appears in our examples for both definitions and declarations."

      • Lesommeil

        But you need initialization, isn't it? Are not definition must have content?

        • nascardriver

          Initialization is optional (but always recommended). If you don't initialize a variable of fundamental type (such as `int`), the variable has an indeterminate value and reading from it causes undefined behavior.

  • Zuhail

    I've a very simple question, in the first point of ODR
    "Within a given file, a function, object, type, or template can only have one definition."
    by 'type' do you mean any fundamental data type as well as user defined data type right?

  • litaci

    i was wondering when the add() is called in main() then the arguments (3,4) is allocated to both forward declared add() or just the definition of add() and how does the compiler or linker distinguishes between them?

  • Aditya

    You wrote "Types, templates, and inline functions and variables are allowed to have identical definitions in different files."

    I think you meant "different definitions in different files" or perhaps "additional definitions in different files"

    • 3li Mot 3alim

      I don't know about files yet, but as he mentioned that a program can have more than one file.
      let's say you have a variable name X in one file, you can have the same variable in different files.

  • keshav

    it doenst happen

    • Bill Gates

      Not sure what "It doesn't happen" means, but....
      This is a perfect example of where you should be implementing a function to get the user input for numbers -
      Lines 24-28 are repeated 4 times - this should be extracted from main and written as a function.
      Also, when doing division you're correct in checking to ensure the denominator is not 0, however the numerator (x in your case) can be 0 - 0 divided by 3 is not undefined and will return the correct answer of 0.

      Your code compiles without error, the only issue seems to be that you have no pause after returning your calculation so the answer flashes briefly and then returns to your menu.

  • Keshav

    Hello Alex and Nascardriver!
    Thanks For all the code learning
    here is a little code.if you like this please comment on it
    umm..... i build it with the help of my brother. Don't worry they only helped me with the loop(while(true)),i gotta be honest here.

    #include <iostream>
    using namespace std;
    int main()
        cout <<"                      Welcome To The Calculator \n";
            /*there is a very big space just because i wanted 'Welcome To The Calculator'to be in the middle of the console*/
        int x;
        int y;
        while (true) {
        cout << "Enter a Number : ";
        cin >> x;
        cout << endl;
        cout << "Enter Another Number : ";
        cin >> y;
        cout << "Press 1 For Addition\n";
        cout << "Press 2 For Subtraction\n";
        cout << "Press 3 For Multiplication\n";
        cout << "Press 4 For Division\n";
        cout << "Press 5 To Exit.\n";
        cout << "Enter Your Choice : ";
        int z;
        cin >> z;
            if (z == 1)
                cout << x << " + " << y << " is " << x + y << "\n";
            else if (z == 2)
                cout << x << " - " << y << " is " << x - y << "\n";
            else if (z == 3)
                cout << x << " * " << y << " is " << x * y << "\n";
            else if (z == 4)
                cout << x << " / " << y << " is " << x / y << "\n";
            else if (z == 5)
                return 0;
                cout << "Enter A Valid Number\n";
            cout << endl;
        return 0;

    • nascardriver


      Please use code tags when posting code.

      - Avoid `using namespace`, it will lead to name collisions.
      - `std::endl` is slower than '\n' and should only be used if you need the text to be printed immediately. '\n' is enough.
      - "\n" is a string, '\n' is a character. Strings are more expensive. If you need only a single character, use single quotes.

  • ThANKS

    I can't believe after studying for two years as a computer science student, thanks to this amazing tutorial site, I just learned that what "definition" and "declaration" really are!!

  • Maybe a wrong word

    1)"Option 1: Reorder the function calls"

    I am not sure about this, but shouldn't "function calls" change to "Option 1: Reorder the function declaration or definition"?

  • Reinz

    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 is both a definition and a declaration.

    In the Author's note section, I think you mistyped here... "int x; a definition, even though it is both...". It should be int x = 0;.

    • nascardriver

      It's correct as written. Variable declaration, even without an initializer, are definitions (Unless declared `extern`).

      • BigScrub

        What exactly is the part of
        int x;
        that makes it a definition? If I were to use x without giving it a value, it would result in undefined behavior, right? When we're talking about defining things in this context, do we mean that we're like defining a section of memory or something along those lines?

        • nascardriver

          It's a variable declaration that is not `extern`, so it's a definition. `x` is uninitialized, reading from it causes undefined behavior. A declaration only means "this thing is somewhere and this is its type", a definitions means "this thing is here", and that's where it gets created, ie. memory is reserved and potentially initialized.

    • 3li Mot 3alim

      I think you don't differentiate between "initialization" and
      "instantiation" or "assignment".
      When we give a value to a variable this is " assignment"
      But, " variables must be initiated before they can be used to store values".
      This instantiation is what "definition" is.
      Also, note that" we use special kind of declaration statement called definition".
      Quotes are from lesson 1.3(introduction to variables).
      Ps(please correct me if I'm wrong)

Leave a Comment

Put all code inside code tags: [code]your code here[/code]