Typically, the base class template will take advantage of the fact that member function bodies (definitions) are not instantiated until long after their declarations, and will use members of the derived class within its own member functions, via the use of a
cast; e.g.: template struct Base { void call() { // ... static_cast(this)->implementation(); // ... } static void staticFunc() { // ... T::staticSubFunc(); // ... } }; struct Derived : public Base { void implementation() { // ... } static void staticSubFunc() { // ... } }; In the above example, the function Base::call(), though
declared before the existence of the struct Derived is known by the compiler (i.e., before Derived is declared), is not actually
instantiated by the compiler until it is actually
called by some later code which occurs
after the declaration of Derived (not shown in the above example), so that at the time the function call is instantiated, the declaration of Derived::implementation() is known. This technique achieves a similar effect to the use of
virtual functions, without the costs (and some flexibility) of
dynamic polymorphism. This particular use of the CRTP has been called "simulated dynamic binding" by some. This pattern is used extensively in the Windows
ATL and
WTL libraries. To elaborate on the above example, consider a base class with
no virtual functions. Whenever the base class calls another member function, it will always call its own base class functions. When we derive a class from this base class, we inherit all the member variables and member functions that were not overridden (no constructors or destructors). If the derived class calls an inherited function which then calls another member function, then that function will never call any derived or overridden member functions in the derived class. However, if base class member functions use CRTP for all member function calls, the overridden functions in the derived class will be selected at compile time. This effectively emulates the virtual function call system at compile time without the costs in size or function call overhead (
VTBL structures, and method lookups, multiple-inheritance VTBL machinery) at the disadvantage of not being able to make this choice at runtime. == Object counter ==