Forward Declaration in C++ Unreal Engine code

Forward Declaration in Unreal Engine. What, Why, How?

Forward Declaration in C++ (Unreal Engine)

In C++ code inside Unreal Engine and others, anytime there is being used an extra type such as component, there's need to attach the type definition. This is done by #include "ReferredSource.h".

Whenever #include "ReferredSource.h" is included in any header .h file, the preprocessor takes all of the content of the included header file, strips out useless parts such as comments, and then pastes all of the contents of that header file into the header file within which is included. By that way, the header file gets bigger as it contains also all the content of the included header files. As the best practice is to keep header files as small as possible, we only want to include things when they are used. To do so, we can use forward declaration.

Let's say, we need to define UCapsuleComponent component within a header file.

UPROPERTY()
UCapsuleComponent* CapsuleComp;

As UCapsuleComponent is not native part of the Pawn class, there would be need to include the USceneComponent type into the class by including #include "Components/SceneComponent.h" into the header file.

If we would not make it, we would get an compilation error error C2039: 'CapsuleComp': is not a member of .... However by including #include "Components/SceneComponent.h" into our header file, we would place all the content of "Components/SceneComponent.h" into our Pawn class as well. This gets really crazy especially when we chain including into multiple classes - the size of any next class grows drastically.

At visualization above, supposing there is used #include "childComponent.h" on each:

  • Capsule.h contains only Capsule.h code.
  • Base.h contains Base.h and Capsule.h code.
  • MyClass.h contains MyClass.h, Base.h and Capsule.h code.
  • MyExtraClass.h contains MyExtraClass.h, MyClass.h, Base.h and Capsule.h code.
  • We could continue further in such way, I guess you got it.

New, let's say we need to create yet another class that will use a type defined in MyClass.h. By including #include "MyClass.h" within our yetAnotherClass.h, we would place a reference with this #include not only at MyClass.h, but also to Base.h and Capsule.h as the MyClass.h includes these classes. As a resul, we would get an analogy of MyExtraClass.h.

As you probably know, part of each .cpp file (even right on the first place), is an #include file referreing to the header .h file of the .cpp file. That means, that header .h file is included within the .cpp file, not the opposite. And, there is verz important to get understand following:

.h header file does not need to know the implementation details of specified class

.h header file does not need to know the implementation details of specified class such as UCapsuleComponent from our example. Basically, header file really does care of how the functions of UCapsuleComponent class are defined or how big the capsule component class is. Simply, a capsule component pointer UCapsuleComponent* is the same size as amy other pointer - it's just an address.

That's why we can use the forward declaration. Forward declaration is processed simply by adding the class keyword before the unknown type (UCapsuleComponent in our case), see:

UPROPERTY()
class UCapsuleComponent* CapsuleCompt;

With the class keyword, there is an information for the compiler, that the UCapsuleComponent is a type. Without that, the compiler does not recognizes the specified variable as the type (as there is not included the type definition), and thus throws an IntelliSense error.

Anyway, as the preprocessor does not throw an IntelliSense error after adding the class keyword, it's still an incomplete type as it does not reffer to any type specification - we still need to specify that type. This is being done in the .cpp file.

Once we add #include "Components/SceneComponent.h" into the .cpp file, the .cpp file has all information it needs, as it has included own .h file as well (so defined variables meet their definition here).

#include "ExampleActor.h"
#include "Components/SceneComponent.h"
...
AExampleActor::AExampleActor()
{
    ...

Same example as above, only with a forward declaring - As of we do not have #include "Base.h" anymore in our "MyClass.h" file (as it's in MyClass.cpp now), when we place #include "MyClass.h" into our new yetAnotherClass.cpp file (we still use forward declaring to allow to include our yetAnotherClass.h anywhere in the future), we get an analogy of the MyExtraClass.cpp file that contain only declaration of a type that we really need.

Remember when defining a C++ code:

  • Include only what you use in .cpp file
  • Include as little as possible in .h file
    • There's no need the header to declare a pointer
    • Header is necessary:
      • to construct an object
      • to access members (functions and variables)
  • #pragma once in header files protects from #include duplications