What's the rule for using forward declarations?

J

John Gabriele

I'm hoping someone can please help me remember the C++ rule: When
you're writing a header file for a class (say, some_namespace::Bar),
and that class makes use of another class (some_namespace::Foo),

-------------------------------- snip --------------------------------
#ifndef GUARD_Foo_HPP
#define GUARD_Foo_HPP

namespace some_namespace {

class Foo
{
// Stuff.
};

} // namespace some_namespace.

#endif // GUARD_Bar_HPP


-------------------------------- snip --------------------------------


you have the option of either #including Foo.hpp,


-------------------------------- snip --------------------------------
#ifndef GUARD_Bar_HPP
#define GUARD_Bar_HPP

#include Foo.hpp

namespace some_namespace {

class Bar
{
// Stuff -- some of which uses Foo's.
};

} // namespace some_namespace.

#endif // GUARD_Bar_HPP


-------------------------------- snip --------------------------------



or else just making a forward declaration:

-------------------------------- snip --------------------------------
#ifndef GUARD_Bar_HPP
#define GUARD_Bar_HPP

namespace some_namespace {

// NOTE: We're *inside* the namespace declaration for this:
class Foo;

class Bar
{
// Stuff -- some of which uses Foo's.
};

} // namespace some_namespace.

#endif // GUARD_Bar_HPP


-------------------------------- snip --------------------------------

I realize that using the forward declaration is always preferable
(so as to make fewer dependencies, as well as less work for the
preprocessor and compiler), but what's the rule for when I can get
away with it?

Thanks.
 
S

Steven T. Hatton

John said:
I'm hoping someone can please help me remember the C++ rule: When
you're writing a header file for a class (say, some_namespace::Bar),
and that class makes use of another class (some_namespace::Foo),

-------------------------------- snip --------------------------------
#ifndef GUARD_Foo_HPP
#define GUARD_Foo_HPP

namespace some_namespace {

class Foo
{
// Stuff.
};

} // namespace some_namespace.

#endif // GUARD_Bar_HPP


-------------------------------- snip --------------------------------


you have the option of either #including Foo.hpp,


-------------------------------- snip --------------------------------
#ifndef GUARD_Bar_HPP
#define GUARD_Bar_HPP

#include Foo.hpp

namespace some_namespace {

class Bar
{
// Stuff -- some of which uses Foo's.
};

} // namespace some_namespace.

#endif // GUARD_Bar_HPP


-------------------------------- snip --------------------------------



or else just making a forward declaration:

-------------------------------- snip --------------------------------
#ifndef GUARD_Bar_HPP
#define GUARD_Bar_HPP

namespace some_namespace {

// NOTE: We're *inside* the namespace declaration for this:
class Foo;

class Bar
{
// Stuff -- some of which uses Foo's.
};

} // namespace some_namespace.

#endif // GUARD_Bar_HPP


-------------------------------- snip --------------------------------

I realize that using the forward declaration is always preferable
(so as to make fewer dependencies, as well as less work for the
preprocessor and compiler), but what's the rule for when I can get
away with it?

Thanks.
Basically you can get away with it as long as you only have pointers and
references in your header. If you have declarations of user defined types
(insted of pointers or references to them), because of the rules for
instantiating these types where they are declared, the compiler has to have
the full definition of the type available in order to allocate memory.
Does this make sense?
 
D

David Hilsee

or else just making a forward declaration:

-------------------------------- snip --------------------------------
#ifndef GUARD_Bar_HPP
#define GUARD_Bar_HPP

namespace some_namespace {

// NOTE: We're *inside* the namespace declaration for this:
class Foo;

class Bar
{
// Stuff -- some of which uses Foo's.
};

} // namespace some_namespace.

#endif // GUARD_Bar_HPP


-------------------------------- snip --------------------------------

I realize that using the forward declaration is always preferable
(so as to make fewer dependencies, as well as less work for the
preprocessor and compiler), but what's the rule for when I can get
away with it?

You can "get away" with a forward declaration when the code that relies on
it is using the type "in name only". That basically means that the code
doesn't need to know the size of the type or the members of the type. This
generally occurs when the type is only being passed around by
pointer/reference. For example, suppose the following was inline inside
your "Bar" class definition:

void foo( Foo* p ) { // OK
p->memfun(); // error
}

void foo2() {
Foo f; // error
}

The FAQ (http://www.parashift.com/c++-faq-lite/) talks about forward
declarations a bit in section 38 ("Miscellaneous technical issues")
questions 11 through 14.
 
J

John Gabriele

David said:
You can "get away" with a forward declaration when the code that relies on
it is using the type "in name only". That basically means that the code
doesn't need to know the size of the type or the members of the type. This
generally occurs when the type is only being passed around by
pointer/reference. For example, suppose the following was inline inside
your "Bar" class definition:

void foo( Foo* p ) { // OK
p->memfun(); // error
}

void foo2() {
Foo f; // error
}

The FAQ (http://www.parashift.com/c++-faq-lite/) talks about forward
declarations a bit in section 38 ("Miscellaneous technical issues")
questions 11 through 14.

Ahh. Thanks Dave (and also Steve). That makes sense.

Also, thanks for the link to the faq. I just dug out my
old dead-tree version, but it looks like there's been many
updates to it since publication in 1999. :)

---J
 
M

Method Man

David Hilsee said:
You can "get away" with a forward declaration when the code that relies on
it is using the type "in name only".

-snip -
void foo( Foo* p ) { // OK
p->memfun(); // error
}

Pardon my ignorance, but when would someone use a type by "name only"? To me
it seems useless to forward declare a class when its member
functions/variables are inaccessable.
 
D

David Hilsee

Pardon my ignorance, but when would someone use a type by "name only"? To me
it seems useless to forward declare a class when its member
functions/variables are inaccessable.

The FAQ has a good example where it is necessary to use forward declarations
in question 38.11 (referenced in my other post). They are also useful for
eliminating compilation dependencies, which is what John Gabriele seems to
be doing. This is the logic behind the pimpl idiom
(http://www.gotw.ca/gotw/024.htm). If you can forward declare a class in a
header instead of defining it in the header, then you won't have to
recompile as many source files when the definition of that class changes. I
have also used "opaque pointers" in C to provide a bit of encapsulation.
One module provided a forward declaration for a type that is used as a
"handle" to something that it didn't want other modules modifying or
depending upon its representation. To do anything with it, the other
modules had to pass the handle to the module that provided it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top