When can I use a forward declaration?

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. ?

6

Put yourself in the compiler’s position: when you forward declare a type, all the compiler knows 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.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>class X;
</code>
<code>class X; </code>
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:

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code>class Foo {
    X *p;
    X &r;
    };
    </code>
    <code>class Foo { X *p; X &r; }; </code>
    class Foo {
        X *p;
        X &r;
    };
    
  • Declare functions or methods which accept/return incomplete types:

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code>void f1(X);
    X f2();
    </code>
    <code>void f1(X); X f2(); </code>
    void f1(X);
    X    f2();
    
  • Define functions or methods which accept/return pointers/references to the incomplete type (but without using its members):

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code>void f3(X*, X&) {}
    X& f4() {}
    X* f5() {}
    </code>
    <code>void f3(X*, X&) {} X& f4() {} X* f5() {} </code>
    void f3(X*, X&) {}
    X&   f4()       {}
    X*   f5()       {}
    

What you cannot do with an incomplete type:

  • Use it as a base class

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code>class Foo : X {} // compiler error!
    </code>
    <code>class Foo : X {} // compiler error! </code>
    class Foo : X {} // compiler error!
    
  • Use it to declare a member:

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code>class Foo {
    X m; // compiler error!
    };
    </code>
    <code>class Foo { X m; // compiler error! }; </code>
    class Foo {
        X m; // compiler error!
    };
    
  • Define functions or methods using this type

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code>void f1(X x) {} // compiler error!
    X f2() {} // compiler error!
    </code>
    <code>void f1(X x) {} // compiler error! X f2() {} // compiler error! </code>
    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

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code>class Foo {
    X *m;
    void method()
    {
    m->someMethod(); // compiler error!
    int i = m->someField; // compiler error!
    }
    };
    </code>
    <code>class Foo { X *m; void method() { m->someMethod(); // compiler error! int i = m->someField; // compiler error! } }; </code>
    class Foo {
        X *m;            
        void method()            
        {
            m->someMethod();      // compiler error!
            int i = m->someField; // compiler error!
        }
    };
    

When it comes to templates, there is no absolute rule: whether you can use an incomplete type as a template parameter is dependent on the way the type is used in the template.

For instance, std::vector<T> requires its parameter to be a complete type, while boost::container::vector<T> does not. Sometimes, a complete type is required only if you use certain member functions; this is the case for std::unique_ptr<T>, for example.

A well-documented template should indicate in its documentation all the requirements of its parameters, including whether they need to be complete types or not.

21

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.

3

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 🙂

2

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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>struct X; // Forward declaration of X
void f1(X* px) {} // Legal: can always use a pointer
void f2(X& x) {} // Legal: can always use a reference
X f3(int); // Legal: return value in function prototype
void f4(X); // Legal: parameter in function prototype
void f5(X) {} // ILLEGAL: *definitions* require complete types
</code>
<code>struct X; // Forward declaration of X void f1(X* px) {} // Legal: can always use a pointer void f2(X& x) {} // Legal: can always use a reference X f3(int); // Legal: return value in function prototype void f4(X); // Legal: parameter in function prototype void f5(X) {} // ILLEGAL: *definitions* require complete types </code>
struct X;              // Forward declaration of X

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

None of the answers so far describes when one can use a forward declaration of a class template. So, here it goes.

A class template can be forwarded declared as:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>template <typename> struct X;
</code>
<code>template <typename> struct X; </code>
template <typename> struct X;

Following the structure of the accepted answer,

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 in another class template:

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code> template <typename T>
    class Foo {
    X<T>* ptr;
    X<T>& ref;
    };
    </code>
    <code> template <typename T> class Foo { X<T>* ptr; X<T>& ref; }; </code>
     template <typename T>
     class Foo {
         X<T>* ptr;
         X<T>& ref;
     };
    
  • Declare a member to be a pointer or a reference to one of its incomplete instantiations:

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code> class Foo {
    X<int>* ptr;
    X<int>& ref;
    };
    </code>
    <code> class Foo { X<int>* ptr; X<int>& ref; }; </code>
     class Foo {
         X<int>* ptr;
         X<int>& ref;
     };
    
  • Declare function templates or member function templates which accept/return incomplete types:

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code> template <typename T>
    void f1(X<T>);
    template <typename T>
    X<T> f2();
    </code>
    <code> template <typename T> void f1(X<T>); template <typename T> X<T> f2(); </code>
     template <typename T>
        void      f1(X<T>);
     template <typename T>
        X<T>    f2();
    
  • Declare functions or member functions which accept/return one of its incomplete instantiations:

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code> void f1(X<int>);
    X<int> f2();
    </code>
    <code> void f1(X<int>); X<int> f2(); </code>
     void      f1(X<int>);
     X<int>    f2();
    
  • Define function templates or member function templates which accept/return pointers/references to the incomplete type (but without using its members):

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code> template <typename T>
    void f3(X<T>*, X<T>&) {}
    template <typename T>
    X<T>& f4(X<T>& in) { return in; }
    template <typename T>
    X<T>* f5(X<T>* in) { return in; }
    </code>
    <code> template <typename T> void f3(X<T>*, X<T>&) {} template <typename T> X<T>& f4(X<T>& in) { return in; } template <typename T> X<T>* f5(X<T>* in) { return in; } </code>
     template <typename T>
        void      f3(X<T>*, X<T>&) {}
     template <typename T>
        X<T>&   f4(X<T>& in) { return in; }
     template <typename T>
        X<T>*   f5(X<T>* in) { return in; }
    
  • Define functions or methods which accept/return pointers/references to one of its incomplete instantiations (but without using its members):

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code> void f3(X<int>*, X<int>&) {}
    X<int>& f4(X<int>& in) { return in; }
    X<int>* f5(X<int>* in) { return in; }
    </code>
    <code> void f3(X<int>*, X<int>&) {} X<int>& f4(X<int>& in) { return in; } X<int>* f5(X<int>* in) { return in; } </code>
     void      f3(X<int>*, X<int>&) {}
     X<int>&   f4(X<int>& in) { return in; }
     X<int>*   f5(X<int>* in) { return in; }
    
  • Use it as a base class of another template class

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code> template <typename T>
    class Foo : X<T> {} // OK as long as X is defined before
    // Foo is instantiated.
    Foo<int> a1; // Compiler error.
    template <typename T> struct X {};
    Foo<int> a2; // OK since X is now defined.
    </code>
    <code> template <typename T> class Foo : X<T> {} // OK as long as X is defined before // Foo is instantiated. Foo<int> a1; // Compiler error. template <typename T> struct X {}; Foo<int> a2; // OK since X is now defined. </code>
     template <typename T>
     class Foo : X<T> {} // OK as long as X is defined before
                         // Foo is instantiated.
    
     Foo<int> a1; // Compiler error.
    
     template <typename T> struct X {};
     Foo<int> a2; // OK since X is now defined.
    
  • Use it to declare a member of another class template:

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code> template <typename T>
    class Foo {
    X<T> m; // OK as long as X is defined before
    // Foo is instantiated.
    };
    Foo<int> a1; // Compiler error.
    template <typename T> struct X {};
    Foo<int> a2; // OK since X is now defined.
    </code>
    <code> template <typename T> class Foo { X<T> m; // OK as long as X is defined before // Foo is instantiated. }; Foo<int> a1; // Compiler error. template <typename T> struct X {}; Foo<int> a2; // OK since X is now defined. </code>
     template <typename T>
     class Foo {
         X<T> m; // OK as long as X is defined before
                 // Foo is instantiated. 
     };
    
     Foo<int> a1; // Compiler error.
    
     template <typename T> struct X {};
     Foo<int> a2; // OK since X is now defined.
    
  • Define function templates or methods using this type

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code> template <typename T>
    void f1(X<T> x) {} // OK if X is defined before calling f1
    template <typename T>
    X<T> f2(){return X<T>(); } // OK if X is defined before calling f2
    void test1()
    {
    f1(X<int>()); // Compiler error
    f2<int>(); // Compiler error
    }
    template <typename T> struct X {};
    void test2()
    {
    f1(X<int>()); // OK since X is defined now
    f2<int>(); // OK since X is defined now
    }
    </code>
    <code> template <typename T> void f1(X<T> x) {} // OK if X is defined before calling f1 template <typename T> X<T> f2(){return X<T>(); } // OK if X is defined before calling f2 void test1() { f1(X<int>()); // Compiler error f2<int>(); // Compiler error } template <typename T> struct X {}; void test2() { f1(X<int>()); // OK since X is defined now f2<int>(); // OK since X is defined now } </code>
     template <typename T>
       void    f1(X<T> x) {}    // OK if X is defined before calling f1
     template <typename T>
       X<T>    f2(){return X<T>(); }  // OK if X is defined before calling f2
    
     void test1()
     {
        f1(X<int>());  // Compiler error
        f2<int>();     // Compiler error
     }
    
     template <typename T> struct X {};
    
     void test2()
     {
        f1(X<int>());  // OK since X is defined now
        f2<int>();     // OK since X is defined now
     }
    

What you cannot do with an incomplete type:

  • Use one of its instantiations as a base class

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code> class Foo : X<int> {} // compiler error!
    </code>
    <code> class Foo : X<int> {} // compiler error! </code>
     class Foo : X<int> {} // compiler error!
    
  • Use one of its instantiations to declare a member:

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code> class Foo {
    X<int> m; // compiler error!
    };
    </code>
    <code> class Foo { X<int> m; // compiler error! }; </code>
     class Foo {
         X<int> m; // compiler error!
     };
    
  • Define functions or methods using one of its instantiations

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code> void f1(X<int> x) {} // compiler error!
    X<int> f2() {return X<int>(); } // compiler error!
    </code>
    <code> void f1(X<int> x) {} // compiler error! X<int> f2() {return X<int>(); } // compiler error! </code>
     void      f1(X<int> x) {}            // compiler error!
     X<int>    f2() {return X<int>(); }   // compiler error!
    
  • Use the methods or fields of one of its instantiations, in fact trying to dereference a variable with incomplete type

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code> class Foo {
    X<int>* m;
    void method()
    {
    m->someMethod(); // compiler error!
    int i = m->someField; // compiler error!
    }
    };
    </code>
    <code> class Foo { X<int>* m; void method() { m->someMethod(); // compiler error! int i = m->someField; // compiler error! } }; </code>
     class Foo {
         X<int>* m;            
         void method()            
         {
             m->someMethod();      // compiler error!
             int i = m->someField; // compiler error!
         }
     };
    
  • Create explicit instantiations of the class template

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code> template struct X<int>;
    </code>
    <code> template struct X<int>; </code>
     template struct X<int>;
    

2

I’m writing this as a separate answer rather than just a comment because I disagree with Luc Touraille’s answer, not on the grounds of legality but for robust software and the danger of misinterpretation.

Specifically, I have an issue with the implied contract of what you expect users of your interface to have to know.

If you are returning or accepting reference types, then you are just saying they can pass through a pointer or reference which they may in turn have known only through a forward declaration.

When you are returning an incomplete type X f2(); then you are saying your caller must have the full type specification of X. They need it in order to create the LHS or temporary object at the call site.

Similarly, if you accept an incomplete type, the caller has to have constructed the object which is the parameter. Even if that object was returned as another incomplete type from a function, the call site needs the full declaration. i.e.:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>class X; // forward for two legal declarations
X returnsX();
void XAcceptor(X);
XAcepptor( returnsX() ); // X declaration needs to be known here
</code>
<code>class X; // forward for two legal declarations X returnsX(); void XAcceptor(X); XAcepptor( returnsX() ); // X declaration needs to be known here </code>
class X;  // forward for two legal declarations 
X returnsX();
void XAcceptor(X);

XAcepptor( returnsX() );  // X declaration needs to be known here

I think there’s an important principle that a header should supply enough information to use it without a dependency requiring other headers. That means header should be able to be included in a compilation unit without causing a compiler error when you use any functions it declares.

Except

  1. If this external dependency is desired behaviour. Instead of using conditional compilation you could have a well-documented requirement for them to supply their own header declaring X. This is an alternative to using #ifdefs and can be a useful way to introduce mocks or other variants.

  2. The important distinction being some template techniques where you are explicitly NOT expected to instantiate them, mentioned just so someone doesn’t get snarky with me.

4

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.

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.

2

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).

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.

1

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.

1

I just want to add one important thing you can do with a forwarded class not mentioned in the answer of Luc Touraille.

What you can do with an incomplete type:

Define functions or methods which accept/return
pointers/references to the incomplete type and forward that pointers/references
to another function.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>void f6(X*) {}
void f7(X&) {}
void f8(X* x_ptr, X& x_ref) { f6(x_ptr); f7(x_ref); }
</code>
<code>void f6(X*) {} void f7(X&) {} void f8(X* x_ptr, X& x_ref) { f6(x_ptr); f7(x_ref); } </code>
void  f6(X*)       {}
void  f7(X&)       {}
void  f8(X* x_ptr, X& x_ref) { f6(x_ptr); f7(x_ref); }

A module can pass through an object of a forward declared class to another module.

1

As, Luc Touraille has already explained it very well where to use and not use forward declaration of the class.

I will just add to that why we need to use it.

We should be using Forward declaration wherever possible to avoid the unwanted dependency injection.

As #include header files are added on multiple files therefore, if we add a header into another header file it will add unwanted dependency injection in various parts of source code which can be avoided by adding #include header into .cpp files wherever possible rather than adding to another header file and use class forward declaration wherever possible in header .h files.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật