Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why must we Forward Declare a class and include the corresponding header file in a header file

Hi I noticed if I include a header file in a .cpp then I can create an object of that header file's class. Like if I includeA.h in main.cpp then I can write A *a; in main.cpp. But this doesn't work if I include a header file in another header file and then try to create the object of that included header file. Like,

file B.h:

#include "A.h"
class B
{
public:
    B(){};
    A *a;
};

I have to add forward declaration of the class A to make it work. Why?

like image 241
Tahlil Avatar asked Jan 19 '13 10:01

Tahlil


1 Answers

Here are the basics:

  • For any type A, if you declare a variable of type A&, A*, A**, A***,etc, then the compiler does not need to know the complete definition of A at the site of variable declaration. All it needs to know that A is a type; that is it. So a forward declaration is enough:

    class A; //forward declaration
    
    class B
    {
       A * pA;  //okay - compiler knows A is a type
       A & refA;/ okay - compiler knows A is a type
    };
    

    The complete definition is not required because the compiler can still compute sizeof(B) which in turn depends on sizeof(A*) and sizeof(A&) — these are known to the compiler, even though it doesn't know sizeof(A). Note that sizeof(A*) is just a size of pointer on that platform (which is usually 4 bytes on 32bit system or 8 bytes on 64bit system).

  • For any type A, if you declare a variable of type A, A[N], A[M]N] etc, then the compiler needs to know the complete definition of type A at the site of variable declaration. A forward declaration would not be enough in this case.

    class A; //forward declaration
    class B
    {
       A a;  //error - the compiler only knows A is a type
             //it doesn't know its size!
    };
    

    But this is correct:

    #include "A.h" //which defines A
    
    class B
    {
       A a;  //okay
    };
    

    The complete definition is required so that the compiler could compute sizeof(A), which is not possible if the compiler doesn't know definition of A.

    Note that definition of a class means "the complete specification of the class members, their types, and whether the class has virtual function(s) or not". If the compiler knows these, it can compute the size of the class.

Knowing these basics, you can decide whether to include headers to other headers or only forward declaration would be enough. If the forward declaration is enough, that is the option you should choose. Include a header only if it is required.

However if you provide forward declaration of A in the header B.h, then you have to include the header file A.h in the implementation file of B which is B.cpp, because in the implementation file of B, you need to access the members of A for which the compiler requires the complete definition of A. Well again, include only if you need to access the members of A. :-)


Sorry I didn't see the last paragraph of your answer. What is confusing me is why do I need the forward declaration also. Doesn't including the header file A.h alone provides complete definition of class A?? –

I don't know what is there in the header file. Also, if in spite of including the header file, you also need to provide the forward declaration, then it implies that the header is implemented incorrectly. I suspect that there is a circular dependency:

  • Make sure that no two header files include each other. For example, if A.h includes B.h, then B.h must not include A.h, directly or indirectly.

  • Use forward declaration and pointer-declaration to break such circular dependency. The logic is pretty much straight-forward. If you cannot include A.h in B.h, which implies you cannot declare A a in B.h (because for this, you have to include the header A.h also). So even though you cannot declare A a, you can still declare A *pA, and for this a forward declaration of A is enough. That way you break the circular dependency.

Hope that helps.

like image 76
Nawaz Avatar answered Oct 04 '22 04:10

Nawaz