21

In my C++ project when do I have to use inclusion (#include "myclass.h") of header files? And when do I have to use forward declaration of the class (class CMyClass;)?

Andrew Barber
  • 39,603
  • 20
  • 94
  • 123
liaK
  • 11,422
  • 11
  • 48
  • 73

5 Answers5

33

As a rule try the forward declaration first. This will reduce compile times etc. If that doesn't compile go for the #include. You have to go for the #include if you need to do any of the following:

  1. Access a member or function of the class.
  2. Use pointer arithmetic.
  3. Use sizeof.
  4. Any RTTI information.
  5. new/delete, copy etc.
  6. Use it by value.
  7. Inherit from it.
  8. Have it as a member.
  9. Instance in a function.

(6,7,8,9 from @Mooing Duck)

They're are probably more but I haven't got my language law hat on today.

Charles Beattie
  • 5,739
  • 1
  • 29
  • 32
  • 4
    you also need to include it to use it by value. So if you inherit from it, have it as a member, or have an instance in a function. – Mooing Duck Jan 13 '12 at 19:08
  • 2
    To ease memorizing - everything except (1) and (4) can be inferred from "if you need to know the size of `CMyClass`'es instance". – Alexander Malakhov Jan 09 '19 at 14:33
  • I had some classes where a member is a pointer to a type that is forward-declared. But when I began to initialize these members (to nullptr) at their declaration, suddenly the forward declaration is insufficient and you have to include the header for the type. This is mostly fine, but some classes include member pointers to each others types, leading to a circular dependency. This circular dependency can be broken by 1) keeping the forward declaration, and 2) NOT initializing the pointer member where it is declared. – MikeOnline Mar 22 '23 at 20:54
13

There are several problems to forward declaration:

  • It is like storing your class name in multiple places -- if you change it in one place, you now have to change it everywhere else. Refactoring becomes a challenge since the code will still compile fine with the changed class name, but linking will fail since the forward declarations refer to an undefined class. If you include the header file and do not use forward declarations, you will catch these problems during compilation.
  • Forward declarations are difficult for others to maintain. For instance, if a header file contains:

    include "MyProject/MyWidgets/MyFooWidgets/FooUtil/Foo.h"
    

    rather than the forward declaration

     class Foo ;  
    

    it is easy for others to find where the class Foo is declared. With forward declaration, it is not that obvious; some IDEs like Eclipse may open the forward declaration when the user tries to open the declaration of a variable.

  • Linking can fail with undefined symbol errors when you include a header file in your code that contains a forward declaration but the actual code definition is located in some other library that you did not link with. It's more convenient to catch this problem at compile time with errors like "Could not find file MyProject/MyWidgets/MyFooWidgets/FooUtil/Foo.h" since then you will know where to look for the corresponding Foo.cpp and identify the library that contains it.

If you think your build is taking too long, then try doing a compile only with no link. If your code takes 10 seconds to compile and 10 minutes to link, the problem has nothing to do with a few extra includes. Similarly, if your header file contains so much stuff in it that it is actually causing a performance problem then it is probably time for you to refactor the content of that file into multiple smaller header files.

So when is it OK to forward declare? If you do it in the same header file as the real declaration.

Example:

class Foo ;

typedef Foo* FooPtr ;
typedef Foo& FooRef ;

class Foo
{
   public:
      Foo( ) ;
      ~Foo( ) ;
}

OR

class TreeNode ;

class Tree
{
private:
   TreeNode m_root ;
}

class TreeNode
{
   void* m_data ;
} ;
Peter O.
  • 32,158
  • 14
  • 82
  • 96
David
  • 131
  • 1
  • 2
  • 2
    I agree with the problems @David lists for forward declarations. But I disagree with the conclusion: "So when is it OK to forward declare? If you do it in the same header file as the real declaration." As other have pointed out, forward declarations are an important tool to decouple physical layout, and speed up builds. // More and more I wonder if we should #include "Foo.hf" - .hf for "a header file that contains nothing except forward declarations." // Of course, I would automatically generate that. – Krazy Glew Oct 15 '12 at 22:06
  • Your 1-st and 3-rd points seems to be invalid. Basically, it the same as If you forward declared `class Foo;` in header and didn't `#include "Foo.h"` in .cpp file - you'll get "use of incomplete type" compilation error. How is it at all possible to get link error? Something to do with precompiled headers (I don't have experience with that)? – Alexander Malakhov Jan 09 '19 at 16:19
  • Regarding your 2-nd point - yes, kind of true. But that happens only when you navigate .h files, in .cpp's it's all OK. And pretty much any IDE has some sort of "search class", with which you can find class by it's name - it will show you all declarations/definitions and usually it's not that hard to figure out where real definition is. @KrazyGlew since David seems to have abandoned StackOverflow, and you agreed with him, I address these questions to you. Would you mind to elaborate a bit? – Alexander Malakhov Jan 09 '19 at 16:27
11

If you only need a pointer to the class and you don't need any knowledge about the class rather than its name, you can use the forward declaration.

ypnos
  • 50,202
  • 14
  • 95
  • 141
4

As a beginner, you should always #include header files when you need to use the types or functions they contain - do not try to "optimise" your build by forward declaring things - this is hardly ever necessary, even on large projects, provided the project is well architected.

The only time you absolutely need a forward declaration is in situations like this:

struct A {
   void f( B b );
};

struct B {
   void f( A a );
};

where each struct (or class) refers to the type of the other. In this case, you need a forward declaration of B to resolve the issue:

struct B;   // forward declaration

struct A {
   void f( B b );
};

struct B {
   void f( A a );
};
  • 1
    Doing maintenance on large projects that have one big "forward_declarations.h" file can be a nightmare since it often confuses the development tool and makes it hard to browse an unfamiliar code base. While it is sometimes important to decrease coupling in your code, don't just automatically put every class into a forward dec file. – bd2357 Feb 09 '16 at 16:27
4

You should strive towards minimizing your #includes both in order to reduce compilation times but also to help with modularity and testability. As @ypnos says, class forwards are excellent when you only need pointers.

For some practical tips on how to reduce header dependencies, see e.g. this article.

Pontus Gagge
  • 17,166
  • 1
  • 38
  • 51