0

If you have a set of header files with include guards, is it really necessary to have forward declarations?

I've been doing this out of habit in my code, and I recommended a colleague add forward declarations to their code, but when they asked whether it was really necessary because of the include guards already present, I was at a bit of a loss. It seems like it's good practice, but wouldn't include guards solve all of the problems that forward declarations do?

Here's an example. Suppose I have a header file like so:

//This is the header file of class B
class MyClassA; //This is forward declaration    

class B{
    private:
        MyClassA *myClass; //pointer to MyClassA
    public:
        B(){}
        ~B(){};

        void print(MyClassA* myClass); //Passing by reference. Not calling any methods of MyClassA.
}

If I know that there is an include guard in MyClassA.h, would the above be better practice than the following? And, if so, why?

#include “MyClassA.h”  

class B{
    private:
        MyClassA *myClass; //pointer to MyClassA
    public:
        B(){}
        ~B(){};

        void print(MyClassA* myClass); //Passing by reference. Not calling any methods of MyClassA.
}

Would the second example also prevent a circular declaration/multiple declaration?

user2701114
  • 141
  • 1
  • 1
  • 5
  • It doesn't solve circular dependencies – JVApen May 22 '19 at 19:02
  • 5
    You generally forward declare when you don't or can't include a header. The fact that they have include guards doesn't really come into play. – François Andrieux May 22 '19 at 19:02
  • Forward declarations are useful when they can be used to avoid having to include the full header (improves compilation time - matters a lot in big projects). Include guards defend against multiple inclusions/definitions - different thing. – Jesper Juhl May 22 '19 at 19:04
  • "is it really necessary to have forward declarations?" - yes, if you have data structures that refer to each other. –  May 22 '19 at 19:05
  • please show an example, there is no obvious relation between include guards and forward declarations, they are rather orthogonal – 463035818_is_not_an_ai May 22 '19 at 19:07
  • 2
    Forward declarations and include guards are totally unrelated matters. The former makes the *compiler* aware of the existance of some type, even though the definition is yet unknown. The latter one prevents the *pre-processor* from including one and the same header multiple times (and in consequence possibly repeating type definitions or ending up in endless include recursions). – Aconcagua May 22 '19 at 19:07
  • @JVApen: I read that header guards do prevent circular dependencies. Is that not true? – user2701114 May 22 '19 at 19:35
  • @FrançoisAndrieux: are there reasons you can't use a header that can't be solved with using header guards? – user2701114 May 22 '19 at 19:36
  • @user2701114 The most common case is probably when [each header needs to include the other](https://stackoverflow.com/questions/625799/resolve-build-errors-due-to-circular-dependency-amongst-classes). – François Andrieux May 22 '19 at 19:37
  • @user2701114 Not exactly, having circular includes gives problems with guards. Though having 1 class with a member, that member type can still use the first in function signatures when using FWDs – JVApen May 22 '19 at 19:53
  • @JVApen I thought an answer like this suggested that circular includes could be solved using header guards: https://stackoverflow.com/questions/3127171/how-are-circular-includes-resolved – user2701114 May 22 '19 at 21:44
  • @formerlyknownas_463035818 I have added an example to my original question – user2701114 May 22 '19 at 21:44
  • @user2701114 yes, at compile level, it can solve the problem, though your code won't work. The answer with the diamond diagram looks more correct – JVApen May 22 '19 at 21:47

1 Answers1

1

You are mixing two unrelated concepts.

  1. You use forward declaration when you need something by name only.

  2. You use include guards to prevent processing of the same code multiple times in a single translation unit, i.e. .cpp file. Whether you use include guards or not is based on the intended use of the .h file. Most of the time, you don't want the contents of the file to be processed multiple times in a .cpp file but there are use cases where allowing that is essential. For the later category of uses, you must not use include guards.

You can combine them anyway you want.

It's ok to:

  1. Use forward declarations AND use include guards.
  2. Use forward declarations AND not use include guards.
  3. Not use forward declarations AND use include guards.
  4. Not use forward declarations AND not use include guards.
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • question has been clarified with an example. Actually OP misunderstood `#include "someheader.h"` as being an include guard. maybe you want to update the answer... – 463035818_is_not_an_ai May 23 '19 at 07:47