| Axel Rogat |
| Objektorientiertes Programmieren mit C++ und JAVA |
|   |
16.1: Parametrisierte Funktionen
| Kapitel 16 |
16.3.1: Array-Klasse  
|
|   |
|   | 16.2 Parametrisierte Klassen |   |
|   |
Genau wie für einzelne Funktionen kann man auch für ganze Klassen eine Schablone angeben, aus der bei Bedarf dann tatsächliche Klassen erzeugt werden. Diese Schablonen heißen auch templates, parametrisierte Klassen, generische Klassen.
Besonders naheliegend ist die Verwendung von Schablonen bei Klassen, die dazu dienen, Objekte in bestimmter Art und Weise zu verwalten -- etwa auf einem Stack, in einem Array, in einem Baum, etc., wobei es auf die Art der Objekte (fast) nicht ankommt.
Beispielsweise wollen wir unsere Stack-Klasse nicht nur zur Speicherung von int, sondern für beliebige Datentypen verwenden können.
Version 1: Wenn man wieder mit Präprozessor-Makros arbeiten möchte, muß man diesmal die gesamte Bibliothek in ein Makro packen!
Version 2: Eine andere Möglichkeit wäre es, in den Knoten nicht direkt den Typ zu speichern (z.B. int), sondern nur einen Pointer darauf. Als Typ für den Pointer könnte man void* verwenden und bei Bedarf in/aus dem richtigen Typ casten. Die Größe bytes des Typs im Speicher wird ein Member. Es müßte jedesmal Speicher für eine Kopie des Objekts angelegt werden, z.B. mit new char[bytes].
So wird leider jede Typüberprüfung ausgeschaltet. Wenn versehentlich Pointer auf andere Objekte als die geplanten an die Elementfunktionen wie push übergeben werden, wird Datenmüll gespeichert. Außerdem verlangsamt sich das Programm durch die doppelte Verzeigerung (neuer Speicher für den Knoten und für die eigentlichen Daten).
Version 3: Die Klassendefinition von früher, durch templates erweitert, sonst beibehalten (insbesondere ohne Copy-Konstruktor und ohne =), sieht wie folgt aus:
Code für eine spezielle Instanz wird funktionenweise erst dann vom Compiler erzeugt, wenn er im Quelltext das erste Mal benötigt wird. Möglicherweise werden also gar nicht immer alle Elementfunktionen übersetzt, insbesondere könnten Fehler längere Zeit gar nicht bemerkt werden.
Instanzen sind schachtelbar, beispielsweise
Der angegebene Typ T kann im Rumpf wie jeder andere Typ verwendet werden. Von ihm können weitere Typen abhängig gemacht werden, wie hier element<T> für die einzelnen Knoten der Liste.
Die Elementfunktionen sind alle automatisch durch T parametrisierte Funktionen -- daher entfällt innerhalb der Klassendefinition eine template-Angabe vor ihrem Prototypen. Werden die Funktionen außerhalb nachgetragen, muß das template explizit (wie bei einfachen typ-parametrisierten Funtktionen) angegeben werden. Ebenso ist mit stack innerhalb der Klassendefinition immer automatisch der durch T parametrisierte Typ gemeint, außerhalb muß explizit die template-Form verwendet werden.
top innerhalb der Implementationsdatei sieht beispielsweise so aus:
|   |
16.1: Parametrisierte Funktionen
| Startseite |
16.3.1: Array-Klasse  
|
|   |