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 onlyCapsule.h
code.Base.h
containsBase.h
andCapsule.h
code.MyClass.h
containsMyClass.h
,Base.h
andCapsule.h
code.MyExtraClass.h
containsMyExtraClass.h
,MyClass.h
,Base.h
andCapsule.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