Interfaces are a contract between a service provider and a service consumer. The C++ Core Guidelines has 20 rules to make them suitable because “interfaces is probably the most important single aspect of code organization”.
Before I dive into the rules, here is an overview of the 20 rules.
- I.1: Make interfaces explicit
- I.2: Avoid global variables
- I.3: Avoid singletons
- I.4: Make interfaces precisely and strongly typed
- I.5: State preconditions (if any)
- I.6: Prefer
Expects()for expressing preconditions
- I.7: State postconditions
- I.8: Prefer
Ensures()for expressing postconditions
- I.9: If an interface is a template, document its parameters using concepts
- I.10: Use exceptions to signal a failure to perform a required task
- I.11: Never transfer ownership by a raw pointer (
- I.12: Declare a pointer that must not be null as
- I.13: Do not pass an array as a single pointer
- I.22: Avoid complex initialization of global objects
- I.23: Keep the number of function arguments low
- I.24: Avoid adjacent unrelated parameters of the same type
- I.25: Prefer abstract classes as interfaces to class hierarchies
- I.26: If you want a cross-compiler ABI, use a C-style subset
- I.27: For stable library ABI, consider the Pimpl idiom
- I.30: Encapsulate rule violations
I will make my discussion of the rules not so elaborate because there are too many rules. My idea is to write in this post about the first ten rules and the next post about the remaining 10. So, let’s start.
I.1: Make interfaces explicit
This rule is about correctness and means: assumptions should be stated in an interface. Otherwise, they are easily overlooked and hard to test.
For example, the function round does not express that its result depends on the invisible dependency round_up.
I.2: Avoid global variables
This rule is obvious, but the emphasis lies on mutable global variables. Global constants are fine because they cannot introduce a dependency into the function and cannot be subject to race conditions.
I.3: Avoid singletons
Singletons are global objects under the hood. Therefore, you should avoid them.
I.4: Make interfaces precisely and strongly typed
The reason for this rule makes it clear: “Types are the simplest and best documentation, have a well-defined meaning, and are guaranteed to be checked at compile time.”
Have a look at an example:
How easy is it to use the function draw_rect incorrectly? Compare this to the function draw_rectangle. The compiler guarantees that the argument is either a Point or a Size object.
You should, therefore, look in your process of code improvement for functions with many built-in type arguments and, even worse, for functions that accept void* as a parameter.
I.5: State preconditions (if any)
If possible, preconditions such that x in double sqrt(double x) must be non-negative should be expressed as assertions.
Expects() from the Guideline support library (GSL) let you express your precondition directly.
Contracts, consisting of preconditions, postconditions, and assertions, may be part of the next C++20 standard. See the proposal p03801.pdf.
I.6: Prefer Expects() for expressing preconditions
That is similar to the previous rule, but the emphasis is on a different aspect. You should use Expects() for expressing preconditions and not, for example, an if expression, a comment, or an assert() statement.
The expression Expects() is easier to spot and may be checkable by the upcoming C++20 standard.
I.7: State postconditions, I.8: Prefer Ensures() for expressing postconditions
Following the arguments of a function, you have to think about its results. Therefore, the postcondition rules are pretty similar to previous precondition rules.
I.9: If an interface is a template, document its parameters using concepts
We will get with high probability with C++20 concepts. Concepts are predicates on template parameters that can be evaluated at compile time. A concept may limit the set of arguments accepted as template parameters. I already wrote four posts about concepts, because there is much more to concepts.
The rule of the C++ Core Guidelines is quite easy. You should apply them.
The generic find algorithm requires that the template parameter Iter is an InputIterator and the underlying value of the template parameter Iter is EqualityComparable. If you invoke the find algorithm with a template argument that does not satisfy this requirement, you will get readable and easily understand the error message.
I. 10: Use exceptions to signal a failure to perform a required task
Here is why: “It should not be possible to ignore an error because that could leave the system or a computation in an undefined (or unexpected) state.”
The rule provides a bad and a good example.
In the wrong case, you can ignore the exception, and your program has undefined behavior.
You should return a pair of values if you didn’t use exceptions. Thanks to C++17 feature structured binding. You can do it quite elegantly.
That is relatively easy to guess. In the next post, I will write about the remaining rules to pointers, initialization of globals objects, function parameters, abstract classes, and ABI (application binary interface). There is a lot to know about good interface design.
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, and Bhavith C Achar.
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,