forward declaration
From Cppwiki
Forward declaration is the technique of declaring a symbol in order to be able to use it without needing its definition.
Macros, enumerated types, or typedefs may not be forward-declared.
Contents |
Functions
A function declaration makes available the full signature of the function, which is all that one needs to use that function.
// declare f void f(); // use f int main() { f(); } // define f void f() { std::cout << "hello world!\n"; }
Classes
A class declaration makes available its name, but not its base classes or members, nor its size.
class MyClass; // extern and static member declarations extern MyClass g_obj; struct A { static MyClass s_obj; }; // typedefs & friendships typedef int MyClass::*PTM; typedef void (MyClass::*PTMF) (); class OtherClass { friend class MyClass; }; // function declarations MyClass Copy(MyClass x); MyClass *GetPtr(); PTM GetPTM(); PTMF GetPTMF(); // pointers, references, pointers-to-member MyClass *p = GetPtr(); MyClass &ref = *p; PTM p_m = GetPTM(); PTMF p_f = GetPTMF(); void UsePTM() { (p->*p_m) = 42; assert((ref.*p_m) == 42): (p->*p_f)(); (ref.*p_f)(); }
Cases where forward declaration is insufficient
class MyClass { public: void Go(); int m_field; }; // sizeof (needs size) const int n = sizeof MyClass; // extern and static member definitions (size, constructor, destructor) MyClass g_obj; MyClass A::s_obj; // nonstatic member declaration (size) struct B { MyClass s_obj; }; // function definition that passes/returns by value (size, copy constructor, destructor) MyClass DoSomething(MyClass x) { return x; } // refer to members by name void UseMembers() { p->Go(); ref.Go(); p_m = &MyClass::m_field; p_f = &MyClass::Go; }
Practical example: chicken and egg
// declare Egg class Egg; class Chicken { public: // use Egg Chicken(const Egg &egg); }; // define Egg class Egg { public: Egg(const Chicken &mother, const Chicken &father); };
Objects
// declare extern int n; class A { public: static int m_n; }; // use int main() { assert(n == 42); assert(A::m_n == 42); } // define int n = 42; int A::m_n = 42;
Templates
Templates can be declared and defined separately. However, templates are almost always instantiated at the point of use, and instantiation requires the definition. Therefore, in general, the definitions must be located in a header file and included before use.
- s_fwd.h:
#ifndef S_FWD_H #define S_FWD_H // declare template <typename T> class S; template <typename T> void f(const S<T> &); #endif
- s.h:
#ifndef S_H #define S_H #include "s_fwd.h" // define f template <typename T> void f(const S<T> &obj) { obj.f(); } // define S / declare S::f template <typename T> class S { public: void f() const; }; // define S::f template <typename T> void S<T>::f() const { std::cout << "hello world!\n"; }; #endif
- main.cpp:
#include "S.h" int main() { S<int> x; f(x); }
If your template is only instantiated for a few types, you can use explicit template instantiation to work around this.
- s.h:
#ifndef S_H #define S_H #include "s_fwd.h" // define S / declare S::f template <typename T> class S { public: void f() const; }; #endif
- s.cpp:
#include "s.h" // define f template <typename T> void f(const S<T> &obj) { obj.f(); } // define S::f template <typename T> void S<T>::f() const { std::cout << "hello world!\n"; }; // define S<int>::f template <> class S<int>; // define f<int> template <> void f<int>();