views:

2195

answers:

9

I am looking for the definition of when I am allowed to do forward declaration of a class in another class's header file:

Am I allowed to do it for a base class, for a class held as a member, for a class passed to member function by reference, etc.

Thank you.

+1  A: 

As long as you don't need the definition (think pointers and references) you can get away with forward declarations. This is why mostly you'd see them in headers while implementation files typically will pull the header for the appropriate definition(s).

dirkgently
+8  A: 

The main rule is that you can only forward-declare classes whose memory layout (and thus member functions and data members) do not need to be known in the file you forward-declare it.

This would rule out base classes and anything but classes used via references and pointers.

Timo Geusch
Almost. You can also refer to "plain" (i.e. non-pointer/reference) incomplete types as parameters or return types in function prototypes.
j_random_hacker
What about classes that I want to use as members of a class that I define in the header file? Can I forward declare them?
Igor Oks
Yes, but in that case you can only use a reference or a pointer to the forward-declared class. But it does let you have members, nevertheless.
Pukku
A: 

You will usually want to use forward declaration in a classes header file when you want to use the other type (class) as a member of the class. You can not use the forward-declared classes methods in the header file because C++ does not know the definition of that class at that point yet. That's logic you have to move into the .cpp-files, but if you are using template-functions you should reduce them to only the part that uses the template and move that function into the header.

Patrick Daryll Glandien
+1  A: 

Take it that forward declaration will get your code to compile (obj is created). Linking however (exe creation) will not be successfull unless the definitions are found.

Sesh
+1  A: 

In file in which you use only Pointer or Reference to a class.And no member/member function should be invoked thought those Pointer/ reference.

with class Foo;//forward declaration

We can declare data members of type Foo* or Foo&.

We can declare (but not define) functions with arguments, and/or return values, of type Foo.

We can declare static data members of type Foo. This is because static data members are defined outside the class definition.

yesraaj
+1  A: 

As well as pointers and references to incomplete types, you can also declare function prototypes that specify parameters and/or return values that are incomplete types. However, you cannot define a function having a parameter or return type that is incomplete, unless it is a pointer or reference.

Examples:

struct X;              // Forward declaration of X

void f1(X* px) {}      // Legal: can always use a pointer/reference
X f2(int);             // Legal: return value in function prototype
void f3(X);            // Legal: parameter in function prototype
void f4(X) {}          // ILLEGAL: *definitions* require complete types
j_random_hacker
+52  A: 

Put yourself in the compiler's position: when you forward declare a type, all the compiler know 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 *pt;
        X &pt;
    };
    
  • Declare functions or methods which accepts/return incomplete types:

    void f1(X);
    X    f2();
    
  • Define functions or methods which accepts/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!
        }
    };
    
Luc Touraille
Very nice explanation. Thank you.
Jesse Emond
+1  A: 

The general rule I follow is not to include any header file unless I have to. So unless I am storing the object of a class as a member variable of my class I won't include it, I'll just use the forward declaration.

Naveen
+1  A: 

Lakos distinguishes between class usage

  1. in-name-only (for which a forward declaration is sufficient) and
  2. in-size (for which the class definition is needed).

I've never seen it pronounced more succinctly :)