Forward Declaration in C++

Dhruvdeep Singh Saini Oct 12, 2023
  1. Forward Declaration in C++
  2. Forward Declaration of Functions in C++
  3. Forward Declaration of Classes in C++
  4. Why the C++ Compiler Needs Forward Declaration
  5. Advantages of Using Forward Declaration in C++
Forward Declaration in C++

This article will explain forward declarations and show why they are necessary for the compiler in C++, along with code examples.

This will also discuss the advantages of using forward declarations, highlight the difference between a declaration and a definition, and show how to use the forward declaration to avoid cyclic dependency error of C++ files.

Forward Declaration in C++

A forward declaration is the declaration of a function’s syntax, i.e., its name, return type, arguments, and the data type of arguments before you use it in your program.

Before defining functions, we include forward declarations to let the compiler know the function is defined somewhere in the program. Forward declaration of functions used in a separate file is formed using the #include to have the file.

Forward Declaration of Functions in C++

Let us see how forward declaration works within a code snippet.

#include <iostream>
using namespace std;

// forward declaration of sub2
int sub2(int A, int B);

int main() {
  cout << "Difference: " << sub2(25, 10);
  return 0;
}

int sub2(int A, int B)  // Defining sub2 here
{
  return A - B;
}

Output:

Difference: 15

Here, we have a function named sub2 that returns the difference of two int parameters passed. We declare sub2 before the main part and then define our function later in the program.

Before we get into the explanation, it is essential to know the distinction between definition and declaration in C++.

  1. Declaration: A declaration provides declaring simple information such as the function’s name, its arguments and their data types, its return type, i.e., the function prototype.
  2. Definition: A definition provides the details of the function declaration and includes the code snippet the task function would perform.

Now, let us get back to the forward declaration. Why was the forward declaration of sub2 needed in the above program?

Let us explain with the same code, this time, without using forward declaration.

#include <iostream>
using namespace std;

int main() {
  cout << "Difference: " << sub2(25, 10);
  return 0;
}

int sub2(int A, int B)  // Defining sub2 here
{
  return A - B;
}

Output:

 error: 'sub2' was not declared in this scope
    6 |     cout << "Difference: " << sub2(25, 10);
      |                               ^~~~

The above program has no problem but still shows an error that the function sub2 was not declared. This is because sub2 is called in line 6 but is undefined until later in line 10.

Since C++ is a top-down parsed language, it constructs a parse tree from the top and needs to know in advance about the functions before they are used. You need not define the function before it is called, but you have to declare it.

You can also define a function, here sub2, before the main function to avoid such errors. However, in a program with multiple functions that call each other or externally included files, the error would persist, which is why we use forward declarations.

Forward Declaration of Classes in C++

You also need a forward declaration of classes in C++. Let us show how.

#include <iostream>
using namespace std;

// Forward declaration of classes One and Two
class One;
class Two;

class One {
  int y;

 public:
  void num(int a)  // Getting input number
  {
    y = a;
  }
  friend int sub2(One, Two);
};
class Two {
  int x;

 public:
  void num(int a)  // Getting input number
  {
    x = a;
  }
  friend int sub2(One, Two);
};
int sub2(One a, Two b)  // Subtraction of two numbers from both classes
{
  int ans = a.y - b.x;
  return ans;
}

int main() {
  Two y;
  One x;

  x.num(25);
  y.num(10);

  cout << "Difference: " << sub2(x, y);
  return 0;
}

Output:

Difference: 15

The above code snippet contains classes, One and Two, both with a num function to get a value and a sub2 function for subtracting two numbers.

Forward declaration of both classes is necessary for the above program since class One includes the friend function sub2 with class Two mentioned in its parameter.

If we remove the forward declaration of classes in the above code snippet, we get an error message:

15 |    [Error] 'Two' has not been declared In function 'int sub2(One, Two)':

The error shows that the compiler needs a forward declaration of functions and classes before using them in a program.

Why the C++ Compiler Needs Forward Declaration

The forward declaration is necessary as it helps the compiler ensure 3 things:

  • The program is correct and has no token spelling mistakes.
  • The arguments of the declared function are correct.
  • The declared function exists in the program and is defined below.

If you did not forward declare the functions, the compiler would create an additional object file containing information with various guesses as to what your function might be.

And the linker (a program that links multiple objects and classes into a single executable object file) would have a linkage issue, as it might have an existing function of the same name but with arguments of a different data type.

For example, assume you have a function int sub2(int a, int b). Without the forward declaration, the linker might get confused with another existing function int sub2(float a, float b).

A compiler validates the code for a clean file with a C++ forward declaration. It would be best to remember that C++ might compile and run such a program in some cases.

However, it would not provide the expected output. This is why the compiler requires forward declarations before implementing or using them in your code.

Advantages of Using Forward Declaration in C++

Forward declarations help the compiler validate your code better and help avoid linkage issues. But it also helps:

  1. Avoid Namespace Polluting: Forward declarations help ensure no code snippet is misplaced and avoid polluting a namespace.

  2. Improve Compilation Time: You can add the declaration of a function into your C++ program by including a header file, and the compiler would parse all the tokens provided in the file, which can take a long time. However, you can avoid this lengthy processing and use forward declaration for the particular classes that you intend to use instead of the whole cpp file.

    This might not impact smaller codes but comes in handy in more significant projects as it can minimize compilation times, thereby reducing time complexity. So instead of including a whole C++ file, you can use a specific class with the .h extension.

  3. Avoid Name Collision: Forward declarations also help ensure there is no collision of token or preprocessor names in the program if there are different projects with matching function or class names.

  4. Break Cyclic Dependency: The forward declaration of a class can solve cyclic references by declaring the particular parts needed in a file and leaving the header out of it.

Avoid Circular Dependency Using Forward Declaration in C++

Two classes related or using each other’s functions create a circular relation. This is known as cyclic or circular dependency.

Suppose there are two classes within your program where both need to use the other. In that case, you will add a header file for one, but it will further try to include the header file for the other circularly dependent class, creating a cycle where each header tries to have the other one.

Let us see how to avoid cyclic dependency:

#include <iostream>
#include <vector>

#include "Two.h"  // Defining Two as it is used in One

class One {
  std::vector<Two> two;
};

int main() { return 0; }

Our program has included another file named Two.h using #include as it is used in class One. Including a class.h file and not a whole other program significantly reduces compilation times, as explained above.

Now, look at the contents of Two.h.

#include "One.h"  // Defining One as it is used in Two

class Two {
  One* a;  // Two uses a pointer of One
};

Two.h contains class Two that uses a pointer of class One. But since both files contain headers to include the other file, you will be stuck in a circular dependency where both files keep calling each other. This can be avoided by using forward declaration instead of adding a header in Two.h by:

#include <iostream>

class One;

class Two {
  One* a;  // Two uses a pointer of One
};

It would be best to remember that forward declaration of a function requires the knowledge of the function’s name and arguments that will be used while defining it and requires duplication of the default values for default parameters.

Hence, you must pay attention when using forward declaration in your programs.