Circular Include in C++

A simple mistake as C++ project grows.

1. Introduction

When a C++ project grows, #include mistakes start showing up as:

  • error: incomplete type
  • “unknown type name”
  • “invalid use of incomplete type”
    and so on …

An include cycle happens when headers form a loop:

Once your include graph contains a loop, it becomes very easy to hit problems where a type is referenced before it’s fully defined.

A minimal circular include example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// A.h
#pragma once
#include "B.h"

class A {
public:
B b;
};

// B.h
#pragma once
#include "A.h"

class B {
public:
A a;
};

2. Solution: Forward Declaration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// A.h
#pragma once
#include "B.h"

class B; // forward declaration of B

class A {
public:
B* b;
};

// B.h
#pragma once
#include "A.h"

class A; // forward declaration of A

class B {
public:
A* a;
};

Forward declarations only work when we store the objects as pointers or references. The following example will fail if we try to store an actual object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// A.h
#pragma once
#include "B.h"

class B; // forward declaration of B

class A {
public:
B* b;
};

// B.h
#pragma once
#include "A.h"

class A; // forward declaration of A

class B {
public:
A a;
};

B.h:8:5: error: field ‘a’ has incomplete type ‘A’
8 | A a;

The most effective pattern to avoid include cycles is to:

  1. Forward declaration in headers.
  2. Includes in cpp files.
1
2
3
4
5
6
7
8
9
10
11
12
13
// A.h
#pragma once

class B;

class A {
B* b;
};

// A.cpp
#include "A.h"
#include "B.h"

3. Inline Functions

Even if you forward declare, inline methods in headers can force full includes. The error messages indicate that we are trying to access the mmeber function of class A, however type completeness is still missing even with forward declaration.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// A.h
#pragma once

#include "B.h"

class B;

class A {
void print() {
printf("print from A\n");
}
B* b;
};

// B.h
#pragma once

#include "A.h"

class A;

class B {
void print(A* a) {
a->print();
}
};

B.h: In member function ‘void B::print(A*)’:
B.h:9:6: error: invalid use of incomplete type ‘class A’
9 | a->print();
| ^~
B.h:5:7: note: forward declaration of ‘class A
5 | class A;
| ^

Author

Joe Chu

Posted on

2026-01-19

Updated on

2026-01-19

Licensed under

Comments