33

I have a class B, and I want to call members from class A. So:

1.

//A.h    
class B; 
class A 
{ 
private:
    B* m_p; 
}; 
    
//a.cpp
#include "B.h"

2.

// A.h
#include "B.h"

class A 
{ 
private: 
    B * impl_; 
}; 

Which way is better and is this two similar when a small project with not too much dependence involves?

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
colddie
  • 1,029
  • 1
  • 15
  • 28

6 Answers6

38

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.
jogojapan
  • 68,383
  • 11
  • 101
  • 131
20

Your first method is a forward declaration. Your second actually includes the class B.

When to use one over the other?

Use the first one when:

  • In the definition of A, you only have a pointer to B, i.e. not a member of B.
  • You never call any function of B from the definition of A. (i.e. all calls to member functions of B happen in the .cpp file where you actually implement A's member functions.)
  • You expect the interface or size of class B to change frequently, but not the interface of A. This way, if B changes, only the contents of a.cpp get recompiled, but a.h (and other files that include a.h) need not change.

Use the second one when:

  • You need to know the size of B. The compiler calculates a class's size using its class definition and the sizes of all its members. For example, if class A has a member that is of type B, then to calculate the size of A, the compiler needs to know the size of B; to know the size of B, you need to include b.h.
    • You need to call functions of class B. In order to know whether you're calling functions that actually exist, the compiler needs to know class B's interface, i.e. you need to include b.h.
maditya
  • 8,626
  • 2
  • 28
  • 28
13

Answer: 1.
Take a look at http://www.umich.edu/~eecs381/handouts/handouts.html

C Header File Guidelines

C++ Header File Guidelines (by David Kieras, EECS Dept., University of Michigan) says:

Guideline #10. If an incomplete declaration of a type X will do, use it instead of #including its header X.h. If another struct or class type X appears only as a pointer or reference type in the contents of a header file, then you should not #include X.h, but just place an incomplete declaration of X (also called a "forward" declaration) near the beginning of the header file, as in: class X; See the handout Incomplete Declarations for more discussion of this powerful and valuable technique. Note that the Standard library includes a header of incomplete declarations that often suffices for the <iostream> library, named <iosfwd>. #include <iosfwd> whenever possible, because the <iostream> header file is extremely large (giant templates!).

Andrey Volk
  • 3,513
  • 2
  • 17
  • 29
0

Just declare the class in your class A's header.

class B;
rubenvb
  • 74,642
  • 33
  • 187
  • 332
Steve Seo
  • 61
  • 1
0

The second is better. It makes the B class a module that you include using the .h file. Consider the case where you subclass B in the future and you update A to use C. In the second case, you only replace the header #include and A's make-up. In the first case, you have to change the forward declaration. Also, in the second case, you define more than just the symbol B.

And as in the comments, you should use #include "B.h" if the header file is in the same directory as the rest of the code.

Bart Friederichs
  • 33,050
  • 15
  • 95
  • 195
0

Well what you're doing is called forward decleration, the reason you would want that is if you had something like class A that uses class B and ALSO class B that uses class A.

In a case where there is only one relation you can certainly use your second choice. If you need the double usage then at least one of your classes declerations would have to use forward decleration

Alon
  • 1,776
  • 13
  • 31