Skip to main content
1 of 9
Luc Touraille
  • 81.9k
  • 16
  • 99
  • 139

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 (or pointers/references to the incomplete type):

     void f1(X, X*, X&);
     X    f2();
     X&   f3();
     X*   f4();
    

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
  • 81.9k
  • 16
  • 99
  • 139