8

In the following example, for instance, what additional benefit could be gained by declaring the class before defining it?

class test;

class test
{
  .....
};
Mehdi Charife
  • 722
  • 1
  • 7
  • 22
navid
  • 81
  • 1
  • 2

6 Answers6

25

C++ (like C) was designed to be implementable by a single-pass compiler. Forward references are necessary in cases where the compiler needs to know that a symbol refers to a class before the class is actually defined. The classic example of this is when two classes need to contain pointers to each other. i.e.

class B;

class A {
  B* b;
};

class B {
  A* a;
};

Without the forward reference to B, the compiler could not successfully parse the definition for A and you can't fix the problem by putting the definition of B before A.

In a language like C#, which needs a two-pass compiler, you don't need forward references

class A {
  B b;
}

class B {
  A a;
}

because the compiler's first pass simply picks up all symbol definitions. When the compiler makes its second pass, it can say "I know B is a class because I saw the definition on my first pass".

Ferruccio
  • 98,941
  • 38
  • 226
  • 299
  • @Lazer: I don't know the specifics for GCC, but most modern C & C++ compilers use multiple passes. They only make one pass over the actual source code and convert it to some sort of internal representation. They then make one or (usually) more optimization passes over this internal representation before the code generation pass. – Ferruccio Jun 24 '10 at 14:52
  • 1
    I thought multi pass is meant for parsing, not for optimization. – Tobias Langner Jun 25 '10 at 06:22
  • 2
    It is strange to me that C and C++ expect the compiler to be single-pass in terms of class scope when merely resolving labels in assembly code compilation requires *that* compiler to make two passes anyway. It seems unduly burdensome on the programmer to require a specific declaration order. – Gravity Sep 09 '11 at 02:33
  • @Ferruccio *"you can't fix the problem by putting the definition of B before A.*" Why is this the case? – Mehdi Charife Jan 06 '23 at 09:51
  • 1
    @MehdiCharife - The two classes refer to each other. Without the initial forward declaration, no matter what order you put them in, the first class definition will reference a class which has not yet been defined. – Ferruccio Jan 06 '23 at 11:08
  • @Ferruccio I think your answer could become more complete by adding the aformentioned explanation. – Mehdi Charife Jan 06 '23 at 11:35
9

The compiler needs the definition of a class if member/methods of that class are accessed or if the size needs to be known. In other cases, a forward declaration is sufficient. This saves you compile time. Example:

class A { 
  B m_b; 
  C* m_ptrC;
}; 

For this class, you need the definition of B (size needed) and only the declaration of C (pointers have fixed size). You only need to include the header of B, not the one of C. A forward declaration of C is sufficient.

a.h:

#ifndef A_H
#define A_H

#include <b.h>
class C;

class A
{
  B m_b;
  C* m_ptrC;
}
#endif

The forward declaration of c (instead of including c.h which is also possible) saves you parsing c.h whenever you include a.h. Across a large project, this may save a lot of compile time. Another benefit is, that changes in c.h do not trigger a recompile for a in this case. I do not know if compiler recognize this if you include c.h instead of forward declaring it.

For more information, try understanding the pimpl-idiom (just google for it. you'll get lots of hits).

Of course - in a.cpp if you actually do something with the pointer to c (e.g. m_ptrC->Add()), you'll need to include c.h. But a.cpp is read only once where the header file is read n times with large n for classes that are used very often in large projects.

Forward declaration also allows for circular dependencies. Example:

class B;

class A {
 B* m_ptrB;
}

class B {
 A* m_ptrA;
}

Just remember - you can't use any information about size & methods if you use forward declarations. This is also the case with 2 classes including each other (one class does not need the forward reference though). I personally think circular references are bad style and you should avoid them if possible.

For additional information: C++ FAQ

Thank you for the comment about the circular dependencies, I simply forgot them.

Tobias Langner
  • 10,634
  • 6
  • 46
  • 76
  • The compiler-efficiency usage legitimate, but I think the circular reference usage is a better starting point when thinking about the purpose of forward references. – Brian Jun 24 '10 at 13:44
4

First, the class is declared, then it is defined.

Declaration: It just tells the compiler: Ok, here's something (method, class, etc.), that can be used by the given name. It just binds the given name to something.

Definition: It tells the compiler: Ok, here's what (and how) the methods, classes, etc. actually do their stuff. If something is defined, then the compiler is caused to actually allocate space for it.

You might have a look at here.

phimuemue
  • 34,669
  • 9
  • 84
  • 115
1

The first line is what's called a forward declaration. It brings the name of the class into the current namespace without actually defining it.

bshields
  • 3,563
  • 16
  • 16
0

Ehm, the question is not very clear. However, the code supplied declares a class test and defines it below, omitting the actual members (...).

Mau
  • 14,234
  • 2
  • 31
  • 52
0

The simple answer is that when you use the first form, you can then hold pointers or references to a class without needing the full implementation. This can be very useful for when two classes tightly interact and their implementations or definitions are hard to separate.

Puppy
  • 144,682
  • 38
  • 256
  • 465