Search code examples
c++headerinclude

c++ header files including each other mutually


I have two classes both defined in separate header files. Each file has a field that is type of other class. Now I included in header of each file the header of other file, but compiler is generating errors. What am i missing?


Solution

  • You cannot have each class have "a field that is type of other class"; that would be a recursive definition. The compiler would not be able to make sense out of it, and it does not even make logical sense: it would result in an infinitely large data structure. The logical impossibility can be illustrated by the "Print Gallery" lithograph by M.C. Escher, or better yet, by this awesome animation of the lithograph:

                                                Animation based on Escher's "Print Gallery" Lithograph, 1956

                             Animation by B. de Smit and H. W. Lenstra - Source: escherdroste.math.leidenuniv.nl
                                                         based on Escher's "Print Gallery" Lithograph, 1956

    (The animation shows a harbor, which contains a building, which contains a painting, which contains a harbor, which contains a building, which contains a painting... ad infinitum.)

    One of the two fields will have to be a pointer, (or a reference, which is nothing but an immutable pointer,) so as to break the recursive containment, and avoid the logical impossibility.

    Which brings us to the next problem:

    If class B is to contain an instance of class A, then obviously, A has to be declared before class B, so that A is already known to the compiler when compiling B.

    But if class A is declared before class B, how can we declare a pointer to B in A? Class B is not known yet at the time that A is compiled!

    The answer to this problem is a special construct known as forward declaration which exists precisely in order to accommodate situations like this. A forward declaration of class B looks like this:

    class B;
    

    All it is telling the compiler is that there will be a class called B. It does not tell the compiler anything about the contents of class B, so there is very little we can do with it, but we can do one thing: declare pointers to B.

    So, the full solution to the problem looks like this:

    (Note: I am omitting header guards for simplicity. Normally they are important, but they are irrelevant to the problem at hand.)

    file "A.h":

    /* This is called a "forward declaration".  We use it to tell the compiler that
       the identifier "B" will from now on stand for a class, and this class will be
       defined later.  We will not be able to make any use of "B" before it has been
       defined, but we will at least be able to declare pointers to it. */
    class B;
    
    class A
    {
        /* We cannot have a field of type "B" here, because it has not yet been
           defined. However, with the forward declaration we have told the compiler
           that "B" is a class, so we can at least have a field which is a pointer 
           to "B". */
        B* pb; 
    }
    

    file "B.h":

    #include "A.h"
    
    class B
    {
       /* the compiler now knows the size of "A", so we can have a field of type "A". */
       A a;
    }