Wie Bjarne Stroustrup betont, ist „C++ eine Multi-Paradigmen-Sprache“. Sie unterstützt viele unterschiedliche Programmierstile bzw. Paradigmen; objektorientierte Programmierung ist nur eines davon. Weitere sind etwa strukturierte und generische Programmierung. C++-Experten wie Andrei Alexandrescu, Scott Meyers und Herb Sutter haben über die Jahre den Einsatz generischer Programmierung gefördert, die häufig mit Modern C++ Design verbunden wird.
Das sagt Andrei Alexandrescu über Modern C++ Design:
Modern C++ Design defines and systematically uses generische Komponenten - highly flexible design artifacts that are mixable and matchable to obtain rich behaviors with a small, orthogonal body of code.Drei Aspekte seiner Sichtweise sind besonders interessant:
- Modern C++ Design definiert und verwendet systematisch generische Komponenten.
- Hochgradig flexibles Design.
- Umfangreiches Verhalten mit einem kleinen, orthogonalen Codebestand erreichen.
Andererseits ist OOP sehr populär: Vererbung und RTTI sind zwei leistungsfähige Mechanismen für den Entwurf einer C++-Anwendung, und viele Entwickler bevorzugen dieses Paradigma gegenüber generischer Programmierung.
Eine gängige Definition von Vererbung lautet:
In object-oriented programming (OOP), Vererbung is when an object or class is based on another object (prototypal inheritance) or class (class-based inheritance), using the same implementation (inheriting from an object or class) specifying implementation to maintain the same behavior (realizing an interface; inheriting behavior). It is a mechanism for code reuse and to allow independent extensions of the original software via public classes and interfaces.Viele C++-Experten empfehlen, Vererbung und dynamischen Polymorphismus nicht übermäßig einzusetzen. Doch was ist eigentlich das Problem an Vererbung?
Kurze Antwort: Sehr starke Kopplung.
Nehmen wir als Beispiel die Implementierung einer Klasse zur Steuerberechnung.

CTaxCalculator arbeitet ausschließlich mit Klassen zusammen, die von ICalculator erben, und kann keine andere Klasse verwenden, selbst wenn diese die Steuer berechnen könnte. Die Implementierung des Rechners ist dadurch stark an ICalculator gekoppelt. Andere Klassenarten lassen sich nur nutzen, wenn zusätzliche Klassen und Schnittstellen eingeführt werden, um diese Einschränkung zu umgehen. Beispielsweise ist das Adapter-Pattern eine Lösung, um die durch Vererbung verursachte enge Kopplung zu umgehen. Einige GoF-Entwurfsmuster existieren gerade deshalb, um Probleme zu lösen, die aus dieser starken Kopplung entstehen.
Generische Programmierung schafft Abhilfe
Mit generischer Programmierung könnte derselbe Steuerrechner so implementiert werden:

Die Klasse CGenericTaxCalculator berechnet die Steuer dagegen mit jedem Typ, der dazu in der Lage ist, ohne dessen konkreten Typ kennen zu müssen. Entscheidend sind die vom Typ implementierten Methoden, nicht die konkrete Klasse, zu der er gehört. Genau das macht generische Programmierung natürlicher und flexibler. Bei der ersten Implementierung ist es dagegen wie in der realen Welt: Ein Unternehmen, das einen Entwickler sucht, akzeptiert nur Absolventen einer bestimmten Hochschule und lehnt alle anderen ab, selbst wenn sie über die erforderlichen Fähigkeiten verfügen. Diese Flexibilität hat jedoch ihren Preis: Der Code kann schwieriger zu verstehen sein. Bei OOP kann ich einfach zur Definition von ICalculator wechseln, um zu sehen, was von diesem Typ erwartet wird. Beim generischen Programmieransatz kann es dagegen schwierig sein, genau zu erkennen, welche Anforderungen der Template-Parameter erfüllen muss: Welche Member muss er enthalten? Welche Constraints müssen erfüllt sein?
C++20 Concepts schaffen Abhilfe
Hier eine kurze Beschreibung der C++20 Concepts:
Concepts are an extension to C++'s Templates, published as an ISO Technical Specification ISO/IEC TS 19217:2015.[1] They are named boolean predicates on template parameters, evaluated at compile time. A concept may be associated with a template (class template, function template, or member function of a class template), in which case it serves as a Constraint: it limits the set of arguments that are accepted as template parameters.Das Concepts-Feature wurde mehrfach verschoben. Die gute Nachricht: C++20 wird dieses interessante Feature enthalten.
In diesem interessanten Dokument findet sich die Motivation hinter dem Concepts-Feature:
The intent of concepts is to model semantic categories (Number, Range, RegularFunction) rather than syntactic restrictions (HasPlus, Array). According to ISO C++ Core Guideline T.20, "The ability to specify a meaningful semantics is a defining characteristic of a true concept, as opposed to a syntactic constraint."Mit Concepts lässt sich das Problem der Constraint-Spezifikation lösen und der Code lesbarer sowie wartbarer gestalten. Boost bietet zwar bereits seit vielen Jahren eine Concepts-Implementierung, doch die direkte Integration in die Sprache macht C++ leistungsfähiger und einzigartiger.
Ein weiterer bekannter Nachteil generischer Programmierung sind die Fehlermeldungen. Manchmal ist kaum nachvollziehbar, warum der Compiler einen Fehler meldet, und es geht viel Zeit verloren, bis die genaue Ursache gefunden ist.
Glücklicherweise verbessert das Concepts-Feature auch die Fehlermeldungen, wie hier.
Zusammenfassung
Wird Vererbung beim OOP-Ansatz übermäßig eingesetzt, führt sie zu einer starken Kopplung zwischen Klassen und zwingt dazu, zusätzliche Klassen allein zur Umgehung dieses Problems einzuführen. Bei generischer Programmierung ist das nicht der Fall. Glücklicherweise wird das bislang fehlende Element für lesbaren, wartbaren und lose gekoppelten Code bald Bestandteil der Sprache sein.
