C circular dependency
Seems like you shouldn't need to include anything in any of the files. A forward declaration of the relevant types should be sufficient:
#ifndef MapTest_vertex_h
#define MapTest_vertex_h
struct edgelist;
typedef struct
{
char* name;
float x, y;
edgelist* edges; // C++ only - not C
} vertex;
#endif
etc. In C coding, you have to write:
struct edgelist;
typedef struct
{
char* name;
float x, y;
struct edgelist* edges;
} vertex;
Circular dependency between C header files
The solution is to simply use some manner of program design. Each "object"/"module" in your program should consist of one h file and one c file. The h file is the public interface. Each such object should only be concerned with its own designated task. It should only include the resources needed to perform that task.
With such a design, there should never be any circular dependencies, or the design is flawed. You should not fix a bad design with various code tricks, you should re-do the design.
But of course the same resource could be included multiple time from different parts of the code. This is why we always use header guards in every single h file.
How to resolve circular struct dependencies in C
The way to do this is to pre-define the structs using empty definition
typedef struct _A A;
typedef struct _B B;
typedef struct _A {
B *b;
} A;
typedef struct _B {
A a;
} B;
You can put the pre-definitions in a global include file to include from wherever you need.
`
Solving a circular dependency - C
It can be useful to define enums in their own file(s), and if you do that here, your problem will disappear.
Handling circular dependencies in C++
Since the C++17 standard you don't need the full EntityBase
class definition for the Scene
class, only a forward declaration:
#pragma once
#include <vector>
#include <string>
class EntityBase; // Forward declaration
class Scene
{
public:
std::vector<EntityBase> entities;
std::string name;
Scene(std::string name);
void addToScene(EntityBase& entityBase);
};
You of course need to include EntityBase.h
anywhere where the entities
vector is used, most notable in the Scene.cpp
source file.
Since EntityBase
is using an actual instance of Scene
you can't do the same with that class and the EntityBase.h
header file. Here you must include the Scene.h
header file.
If you build targeting an older C++ standard (C++14 or earlier) then you must have the full definition of the EntityBase
class for the vector.
As a possible workaround either make entities
a vector of pointers to EntityBase
; Or make EntityBase::scene
a pointer and use forward declaration in the EntityBase.h
header file instead. Or a combination of both.
Resolve build errors due to circular dependency amongst classes
The way to think about this is to "think like a compiler".
Imagine you are writing a compiler. And you see code like this.
// file: A.h
class A {
B _b;
};
// file: B.h
class B {
A _a;
};
// file main.cc
#include "A.h"
#include "B.h"
int main(...) {
A a;
}
When you are compiling the .cc file (remember that the .cc and not the .h is the unit of compilation), you need to allocate space for object A
. So, well, how much space then? Enough to store B
! What's the size of B
then? Enough to store A
! Oops.
Clearly a circular reference that you must break.
You can break it by allowing the compiler to instead reserve as much space as it knows about upfront - pointers and references, for example, will always be 32 or 64 bits (depending on the architecture) and so if you replaced (either one) by a pointer or reference, things would be great. Let's say we replace in A
:
// file: A.h
class A {
// both these are fine, so are various const versions of the same.
B& _b_ref;
B* _b_ptr;
};
Now things are better. Somewhat. main()
still says:
// file: main.cc
#include "A.h" // <-- Houston, we have a problem
#include
, for all extents and purposes (if you take the preprocessor out) just copies the file into the .cc. So really, the .cc looks like:
// file: partially_pre_processed_main.cc
class A {
B& _b_ref;
B* _b_ptr;
};
#include "B.h"
int main (...) {
A a;
}
You can see why the compiler can't deal with this - it has no idea what B
is - it has never even seen the symbol before.
So let's tell the compiler about B
. This is known as a forward declaration, and is discussed further in this answer.
// main.cc
class B;
#include "A.h"
#include "B.h"
int main (...) {
A a;
}
This works. It is not great. But at this point you should have an understanding of the circular reference problem and what we did to "fix" it, albeit the fix is bad.
The reason this fix is bad is because the next person to #include "A.h"
will have to declare B
before they can use it and will get a terrible #include
error. So let's move the declaration into A.h itself.
// file: A.h
class B;
class A {
B* _b; // or any of the other variants.
};
And in B.h, at this point, you can just #include "A.h"
directly.
// file: B.h
#include "A.h"
class B {
// note that this is cool because the compiler knows by this time
// how much space A will need.
A _a;
}
HTH.
Related Topics
Non-Type Variadic Function Templates in C++11
Stopping an Infinite Loop in C++ When Key Is Pressed
Finding C++ Interval Tree Algorithm Implementation
Using Boost::Iostreams::Tee_Device
Factor a Large Number Efficiently with Gmp
Modifying Reference Member from Const Member Function in C++
Enumerate Com Object (Idispatch) Methods Using Atl
How to Analyze Program Running Time
Nat-Traversal Implementation for P2P Connection
Writing X264 from Opencv 3 with Ffmpeg on Linux
Read and Write on Serial Port in Ubuntu with C/C++ and Libserial
Why How to Implicitly Convert an Int Literal to an Int * in C But Not in C++