Jump to content

  • Log In with Google      Sign In   
  • Create Account


#ActualVReality

Posted 01 August 2013 - 05:06 PM

Meerul264,

You may have been misinformed about forward declarations.  One thing a forward declaration does not give is visibility on class members. 

 

Gaining Visibility on Class Definitions

 

This is generally done by including headers.  As zacaj shows above, A.cpp can include B.h to see and use B's public members, and B.cpp can include A.h to see and use A's public members. 

 

A.h:

class A
{/*members declared here*/};

B.h:

class B
{/*members declared here*/};

A.cpp:

#include "A.h" // Includes A's class definition (so members declared in it can be defined here).
#include "B.h" // Includes B's class definition (so members of A can see and use B and its public members).
...

B.cpp:

#include "B.h" // Includes B's class definition (so members declared in it can be defined here).
#include "A.h" // Includes A's class definition (so members of B can see and use A and its public members).
...

Header inclusion gets you visibility on a class definition.  Forward declarations are neither necessary nor sufficient.

 

When to Use Forward Declarations

 

Forward declarations are for cases in which the compiler needs to know that something is defined elsewhere, but doesn't need the details of that definition. 

 

A.h:

class B; // Forward declaration

class A
{B * pB;};  // Use of B, but not of B's definition

In this case, the compiler doesn't need to know anything about B here except that it's a class which is defined somewhere.

 

Note that we could include B.h here instead.  However, that would unnecessarily include B.h everywhere that A.h is included (which is bad for compile times). 

 

Also, there are cases when you can't include a header:

 

A.h:

#include "B.h" // Error - B.h includes this file

class A
{B * pB;}; 

B.h:

#include "A.h" // Error - A.h includes this file

class B
{A * pA};

Trying to include header files here results in infinite include recusion.

 

Include guards and "#pragma Once" can't solve this issue.  They will prevent the recursion, but will result in a reference to an undefined type.  If you can imagine the compiler reading A.h, it would include B.h, whithin which it would effectively ignore the directive to include A.h, then would parse the definition of B, which includes a reference to A, which would not yet be defined.

 

Forward declaration is the only way to make this work.

 

That being said, you'll run into other problems when you have classes mutually depending on each other in this way.  As mentioned above, in this case you should probably re-design to reduce dependancies.  I generally only use forward declarations to eliminate unnecessary include directives.

 

Forward Declarations Can Only Do So Much

 

Note that forward declarations allow A and B to contain pointers to each other because the compiler doesn't need to know the details of a class to define a pointer to that class.  This wouldn't work for member objects.

 

A.h:

#include "B.h" 

class A
{B MyB;}; 

In this case we must include the full definition of B.  The compiler needs its details in order to fully define A.  Because of this, there's no way for B to then contain a member of type A.  Forward declarations don't make recursive class definitions possible.


#1VReality

Posted 30 July 2013 - 01:36 PM

Meerul264,

You may have been misinformed about forward declarations.  One thing a forward declaration does not give is visibility on class members. 

 

Gaining Visibility on Class Definitions

 

This is generally done by including headers.  As zacaj shows above, A.cpp can include B.h to see and use B's public members, and B.cpp can include A.h to see and use A's public members. 

 

A.h:

class A
{/*members declared here*/};

B.h:

class B
{/*members declared here*/};

A.cpp:

#include "A.h" // Includes A's class definition (so members declared in it can be defined here).
#include "B.h" // Includes B's class definition (so members of A can see and use B and its public members).
...

B.cpp:

#include "B.h" // Includes B's class definition (so members declared in it can be defined here).
#include "A.h" // Includes A's class definition (so members of B can see and use A and its public members).
...

Header inclusion gets you visibility on a class definition.  Forward declarations are neither necessary nor sufficient.

 

When to Use Forward Declarations

 

Forward declarations are for cases in which the compiler needs to know that something is defined elsewhere, but doesn't need the details of that definition. 

 

A.h:

class B; // Forward declaration

class A
{B * pB;};  // Use of B, but not of B's definition

In this case, the compiler doesn't need to know anything about B here except that it's a class which is defined somewhere.

 

Note that we could include B.h here instead.  However, that would unnecessarily include B.h everywhere that A.h is included (which is bad for compile times). 

 

Also, there are cases when you can't include a header:

 

A.h:

#include "B.h" // Error - B.h includes this file

class A
{B * pB;}; 

B.h:

#include "A.h" // Error - A.h includes this file

class B
{A * pA};

Trying to include header files here results in infinite include recusion.

 

Include guards and "#pragma Once" can't solve this issue.  They will prevent the recursion, but will result in a reference to an undefined type.  If you can imagine the compiler reading A.h, it would include B.h, whithin which it would effectively ignore the directive to include A.h, then would parse the definition of B, which includes a reference to A, which would not yet be defined.

 

Forward declaration is the only way to solve this problem.

 

When Forward Declarations Can't Help You

 

Note that forward declarations allow A and B to contain pointers to eachother because the compiler doesn't need to know the details of a class to define a pointer to that class.  This wouldn't work for member objects.

 

A.h:

#include "B.h" 

class A
{B MyB;}; 

In this case we must include the full definition of B.  The compiler needs its details in order to fully define A.  Because of this, there's no way for B to then contain a member of type A.  Forward declarations don't make recursive class definitions possible.


PARTNERS