Hello! I’m developing in blueprints for a couple of years and trying to transit to c++.
Can someone explain to me how to avoid cirular dependencies?
Let’s say I have a Controller and this Controller owns a StateMachine Class. Both have references to each other.
Wouldn’t I have to add #include “Controller.h” to the StateMachine header and “StateMachine.h” to the Controller header to hold variables of each other?
Your custom header files generally should not contain (and should not need to contain) includes for your other custom header files.
Instead, your header files should contain forward declarations to classes referenced in the header file, and then the cpp file would contain an include to the other header files. So, in general, your cpp files include header files, and header files just include forward declarations.
There are exceptions, but that general approach will largely eliminate circular dependencies.
I’ll briefly expand on Kelby’s post
controller.h:
class FMyStateMachine; // forward-declaration
class FMyController {
FMyStateMachine* StateMachine = nullptr; // pointer is fine
void DoThing(FMyStateMachine& StateMachine); // reference is also fine
inline void DoInlineThing() {
StateMachine->Transition(); // NOT OK, using undefined type (compiler doesn't know about Transition() function). Function implementation needs to be in the cpp file.
}
};
statemachine.h:
class FMyController; // forward-declaration
class FMyStateMachine {
FMyController* Controller = nullptr;
void Transition();
}
If you want say a structure that’s contained directly inside some other class or struct (not just referenced), you’ll need to include the file it’s defined in. You can still forward-declare the parent class in the struct’s header if you need a reference from struct to parent.
Thanks a lot!
So if I want to use a StateMachine function inside the Controllers .cpp i need to:
-
forward declare (class FStateMachine;) inside Controller.h
And to use StateMachine->Transition(); i have to -
add #include “StateMachine.h” to the Controller.cpp, is this correct?
so the forward-declaration is to inform there will be a class named like that, and the header include in the .cpp gives me access to it’s function?
Yeah you got it. Type names and struct
vs class
need to match. Forward-declared types can be used if all you need to know is where in memory to find an object (pointer or ref). If you need to know the size, access any member variable, or call any function on the type, then you need the full definition (so you need the include with the definition, unless the type is defined at the top of the cpp).