Forward Declaration VS Include

Forward Declaration vs Include

Case 1 will produce an "incomplete type" error when you compile B.cpp. Because class B contains a class A object, the definition (and in particular the size) of class A is required to be complete before the definition of class B.

Alternatively, you could choose to make some_variable a pointer or reference to class A, and in that case your forward declaration would be sufficient in B.h. You'd still need a full definition of A in B.cpp (assuming you made actual use of the A member functions/data).

Include in header file vs. forward-declare and include in .cpp

Your first way of doing it means that in a.h, the existence of class B is known, but not its definition. This limits what you can do with B inside a.h. For example, you can have variables of type B *, but not variables of type B (because for a declaration of a variable of type B the compiler must be able to see the full definition of B). Also, if you have variables of type B *, you can't dereference the pointer (because for that, too, the definition of B must be known).

Therefore, your second choice – which doesn't have these problems – is preferred, and this is what most people use most of the time.

It's only special cases in which the first method may be useful. For example:

  • If the .h files include each other (but then you may get a number of further problems, also regarding include-guards; this is generally difficult and to be avoided);
  • If b.h is extremely large and complex, so you'd like to avoid including it wherever possible because it slows down the compilation process.

Should one use forward declarations instead of includes wherever possible?

The forward-declaration method is almost always better. (I can't think of a situation where including a file where you can use a forward declaration is better, but I'm not gonna say it's always better just in case).

There are no downsides to forward-declaring classes, but I can think of some downsides for including headers unnecessarily:

  • longer compilation time, since all translation units including C.h will also include A.h, although they might not need it.

  • possibly including other headers you don't need indirectly

  • polluting the translation unit with symbols you don't need

  • you might need to recompile source files that include that header if it changes (@PeterWood)

C/C++ Forward declaration vs. Include

What is happening when you include some file and what is happening when you forward declare some function/class?

When you include a file, its contents get "copy and pasted" into the inclusion source by the preprocessor. When you forward declare a function/class you are declaring an incomplete type, letting the rest of the translation unit know that a function/class with that name exist and making it usable within context where an incomplete declaration is allowed.

If two files include the same file will the first one success to read all the function the second will fail but still be able to use the functions??

If the included file includes proper include guards, the second inclusion within the same translation unit will be effectively a no-op. If two different source files include that same header file, the full content will be included in both files.

What happens when I forward declare some function? Is this function now "saved" and I can use it anywhere or it's known only for the same file? then why two files with include(to a file with guards) will work?

The function can only be used within the translation unit that contains the forward declaration. Generally each source file (.cpp) is a different translation unit, macro definitions (those of the header guards) as well as declarations/definitions are valid within that translation unit. Header guards prevent the same header file from being included more than once within the same translation unit, to prevent multiple declaration errors.

Forward declare or #include first?

Always headers first, then forward declares. Otherwise you risk unnecessary dependencies such that you'll need to repeat the forward declares whenever you include donna.h, for example (because you have inadvertently introduced a need for it).

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

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.

When can I use a forward declaration?

Put yourself in the compiler's position: when you forward declare a type, all the compiler knows is that this type exists; it knows nothing about its size, members, or methods. This is why it's called an incomplete type. Therefore, you cannot use the type to declare a member, or a base class, since the compiler would need to know the layout of the type.

Assuming the following forward declaration.

class X;

Here's what you can and cannot do.

What you can do with an incomplete type:

  • Declare a member to be a pointer or a reference to the incomplete type:

    class Foo {
    X *p;
    X &r;
    };
  • Declare functions or methods which accept/return incomplete types:

    void f1(X);
    X f2();
  • Define functions or methods which accept/return pointers/references to the incomplete type (but without using its members):

    void f3(X*, X&) {}
    X& f4() {}
    X* f5() {}

What you cannot do with an incomplete type:

  • Use it as a base class

    class Foo : X {} // compiler error!
  • Use it to declare a member:

    class Foo {
    X m; // compiler error!
    };
  • Define functions or methods using this type

    void f1(X x) {} // compiler error!
    X f2() {} // compiler error!
  • Use its methods or fields, in fact trying to dereference a variable with incomplete type

    class Foo {
    X *m;
    void method()
    {
    m->someMethod(); // compiler error!
    int i = m->someField; // compiler error!
    }
    };

When it comes to templates, there is no absolute rule: whether you can use an incomplete type as a template parameter is dependent on the way the type is used in the template.

For instance, std::vector<T> requires its parameter to be a complete type, while boost::container::vector<T> does not. Sometimes, a complete type is required only if you use certain member functions; this is the case for std::unique_ptr<T>, for example.

A well-documented template should indicate in its documentation all the requirements of its parameters, including whether they need to be complete types or not.



Related Topics



Leave a reply



Submit