In my last post, “Dynamic and Static Polymorphism“, I introduced dynamic polymorphism. Today, I continue with static polymorphism and present a very interesting idiom in C++: curiously recurring template pattern (CRTP).
A short recap. This is where I left in my last post.
Dynamic Polymorphism is based on object orientation and enables us to separate between the interface and the implementation of a class hierarchy. To get late dynamic dispatch, you need two ingredients: virtuality and an indirection such as a pointer or a reference. The following program exemplified dynamic polymorphism:
Static polymorphism is based on templates. Refactor the program using the Curiously Recurring Template Pattern (CRTP).
Before I refactor the previous program
dispatchDynamicPolymorphism.cpp, here is the key idea of CRTP: A class
Derived derives from a class template
Derived as a template argument.
Here is the pure nature of CRTP:
I use in the function template
execute (line 1) static polymorphism. Each base invoked the method
base.interface. The member function
Base::interface (line 2) is the key point of the CRTP idiom. The member function dispatches to the implementation of the derived class: static_cast<Derived*>(this)->implementation(). That is possible because the method will be instantiated when called. At this point in time the derived classes
Derived1, Derived2, and Derived3 are fully defined. Therefore, the method Base::interface can use the implementation of its derived classes. Pretty interesting is the member function Base::implementation (line 3). This function plays the role of a default implementation for the static polymorphism for the class
Derived3 (line 4).
Here is the output of the program:
Now, let me take the next step and refactor the program
In this case, all concrete classes (lines 3, 4, and 5) derive from the base class
MessageSeverity. The member function
writeMessage is the interface that dispatches to the concrete implementations
writeMessageImplementation. To achieve this, the object will be upcasted to the
ConcreteMessage: static_cast<ConcreteMessage*>(this)->writeMessageImplementation();. This is the static dispatch at compile time and coined the name for this technique: static polymorphism.
It took me time to get used to it, but applying the static polymorphism in line (6) is quite easy.
In the end, I want to compare dynamic and static polymorphism in a few words:
Dynamic polymorphism happens at run time, and static polymorphism at compile time. Dynamic polymorphism typically requires a pointer indirection at run time (read the post “Demystifying virtual functions, Vtable, and VPTR in C++“), but static polymorphism has no performance costs at run time. Admittedly, there is a reason why the idiom curiously recurring template pattern (CRTP) has the name curious inside. For beginners, the idiom is quite challenging to understand. So, what should you use?
First of all, don’t overestimate the costs of a virtual dispatch. In most cases, you can ignore them. Read the excellent paper “Technical Report on C++ Performance” for details. It’s pretty dated but has in section 5.3.3 exciting numbers about the additional costs of virtual function calls. If you are still concerned about performance, there is only one cure: measure. Put your performance tests under version control. Always rerun them if something in your setup consisting of your hardware, compiler, or compiler version changes because this invalidates your previous performance numbers.
In the end, code is way more often read the written. Therefore, you should use the techniques your team is most comfortable with.
Mixins are a widespread technique in Python. They allow you to change the behavior of a class using multiple inheritances. Thanks to CRTP, we also have mixins in C++. Read about them in my next post.
Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, and Marco Parri Empoli.
Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.
|My special thanks to Embarcadero|
|My special thanks to PVS-Studio|
|My special thanks to Tipi.build|
|My special thanks to Take Up Code|
I’m happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.
- Embedded Programmierung mit modernem C++ 12.12.2023 – 14.12.2023 (Präsenzschulung, Termingarantie)
Standard Seminars (English/German)
Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.
- C++ – The Core Language
- C++ – The Standard Library
- C++ – Compact
- C++11 and C++14
- Concurrency with Modern C++
- Design Pattern and Architectural Pattern with C++
- Embedded Programming with Modern C++
- Generic Programming (Templates) with C++
- Clean Code with Modern C++
- Phone: +49 7472 917441
- Mobil:: +49 176 5506 5086
- Mail: schulung@ModernesCpp.de
- German Seminar Page: www.ModernesCpp.de
- Mentoring Page: www.ModernesCpp.org
Modernes C++ Mentoring,