Menu
Coddy logo textTech

Klassentemplates

Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy — Lektion 65 von 104.

Genauso wie Funktions-Templates es Ihnen ermöglichen, typunabhängige Funktionen zu schreiben, lassen Sie Klassen-Templates typunabhängige Klassen erstellen. So funktionieren Container wie std::vector – Sie definieren die Struktur einmal, und der Compiler generiert spezifische Versionen für jeden Typ, den Sie verwenden.

template <typename T>
class Box {
    T value;
public:
    Box(T v) : value(v) {}
    T getValue() const { return value; }
    void setValue(T v) { value = v; }
};

int main() {
    Box<int> intBox(42);
    Box<std::string> strBox("Hello");
    
    std::cout << intBox.getValue() << std::endl;  // 42
    std::cout << strBox.getValue() << std::endl;  // Hello
}

Im Gegensatz zu Funktions-Templates müssen Sie den Typ explizit angeben, wenn Sie Objekte aus Klassen-Templates unter Verwendung von spitzen Klammern erstellen. Der Compiler generiert dann eine vollständige Klassendefinition für diesen spezifischen Typ.

Klassentemplates können mehrere Typparameter und sogar Nicht-Typparameter wie Ganzzahlen haben:

template <typename T, int Size>
class FixedArray {
    T data[Size];
public:
    T& operator[](int index) { return data[index]; }
    int size() const { return Size; }
};

FixedArray<double, 5> arr;  // Array von 5 Doubles
arr[0] = 3.14;

Wenn Sie Elementfunktionen außerhalb der Klasse definieren, müssen Sie die Template-Deklaration wiederholen:

template <typename T>
class Container {
    T* data;
public:
    Container();
    ~Container();
};

template <typename T>
Container<T>::Container() : data(nullptr) {}

template <typename T>
Container<T>::~Container() { delete data; }

Klassentemplates bilden die Grundlage der generischen Programmierung in C++ und ermöglichen es Ihnen, wiederverwendbare Datenstrukturen zu schreiben, die mit jedem Typ funktionieren.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein generisches Speichersystem unter Verwendung von Klassentemplates erstellen, um einen flexiblen Container zu bauen, der jeden Datentyp aufnehmen kann. Sie werden Ihre Template-Klasse in einer Header-Datei organisieren und ihre Vielseitigkeit mit verschiedenen Typen in Ihrem Hauptprogramm demonstrieren.

Sie werden zwei Dateien erstellen:

  • Storage.h: Definieren Sie ein Klassentemplate namens Storage, das als einfacher Container für einen einzelnen Wert mit einigen nützlichen Operationen fungiert:

    Ihr Storage-Template sollte Folgendes haben:

    • Ein privates Mitglied, um den gespeicherten Wert zu halten
    • Einen Konstruktor, der einen Initialwert entgegennimmt
    • Eine getValue()-Methode, die den gespeicherten Wert zurückgibt
    • Eine setValue()-Methode, die den gespeicherten Wert aktualisiert
    • Eine isEmpty()-Methode, die true zurückgibt, wenn der Wert dem standardmäßig konstruierten Wert vom Typ T entspricht, andernfalls false

    Erstellen Sie außerdem ein Klassentemplate namens Pair mit zwei Typparametern, das zwei zusammengehörige Werte speichert:

    • Private Mitglieder für den ersten und zweiten Wert (von potenziell unterschiedlichen Typen)
    • Einen Konstruktor, der beide Werte initialisiert
    • Methoden getFirst() und getSecond(), um die jeweiligen Werte abzurufen
    • Eine display()-Methode, die Folgendes ausgibt: (<first>, <second>)
  • main.cpp: Lesen Sie vier Eingaben ein (jede in einer separaten Zeile):
    1. Einen Integer-Wert
    2. Einen neuen Integer-Wert
    3. Einen String-Wert
    4. Einen Double-Wert

    Demonstrieren Sie Ihre Templates durch:

    1. Erstellen eines Storage<int> mit dem ersten Integer und Ausgabe von: Int storage: <value>
    2. Aktualisieren desselben mit dem zweiten Integer unter Verwendung von setValue(), dann Ausgabe von: Updated: <value>
    3. Erstellen eines Storage<std::string> mit der String-Eingabe und Ausgabe von: String storage: <value>
    4. Prüfen, ob der String-Speicher leer ist, und Ausgabe von: Is empty: <true/false> (geben Sie true oder false aus)
    5. Erstellen eines Pair<std::string, double> mit den String- und Double-Werten, dann Aufruf von display()
    6. Erstellen eines Pair<int, int> mit beiden Integer-Eingaben, dann Aufruf von display()

Zum Beispiel bei den Eingaben 42, 100, Hello und 3.14:

Int storage: 42
Updated: 100
String storage: Hello
Is empty: false
(Hello, 3.14)
(42, 100)

Beachten Sie, wie dasselbe Storage-Template nahtlos mit Integern und Strings funktioniert und wie Pair verschiedene Typen miteinander kombinieren kann. Der Compiler generiert separate Klassendefinitionen für jede Typkombination, die Sie verwenden. Denken Sie daran, die Syntax template <typename T> für Templates mit einem Typ und template <typename T, typename U> für Templates mit mehreren Typparametern zu verwenden.

Spickzettel

Klassentemplates ermöglichen es Ihnen, typunabhängige Klassen zu erstellen. Der Compiler generiert spezifische Versionen für jeden Typ, den Sie verwenden.

Grundlegendes Klassentemplate

template <typename T>
class Box {
    T value;
public:
    Box(T v) : value(v) {}
    T getValue() const { return value; }
    void setValue(T v) { value = v; }
};

Beim Erstellen von Objekten aus Klassentemplates müssen Sie den Typ explizit mit spitzen Klammern angeben:

Box<int> intBox(42);
Box<std::string> strBox("Hello");

Mehrere Typparameter

Klassentemplates können mehrere Typparameter haben:

template <typename T, typename U>
class Pair {
    T first;
    U second;
public:
    Pair(T f, U s) : first(f), second(s) {}
};

Nicht-Typparameter

Templates können auch Nicht-Typparameter wie Ganzzahlen akzeptieren:

template <typename T, int Size>
class FixedArray {
    T data[Size];
public:
    int size() const { return Size; }
};

FixedArray<double, 5> arr;  // Array aus 5 Doubles

Definition von Elementfunktionen außerhalb der Klasse

Wenn Sie Elementfunktionen außerhalb der Klasse definieren, wiederholen Sie die Template-Deklaration:

template <typename T>
class Container {
    T* data;
public:
    Container();
    ~Container();
};

template <typename T>
Container<T>::Container() : data(nullptr) {}

template <typename T>
Container<T>::~Container() { delete data; }

Probier es selbst

#include <iostream>
#include <string>
#include "Storage.h"

using namespace std;

int main() {
    // Eingaben lesen
    int intValue1;
    int intValue2;
    string strValue;
    double doubleValue;
    
    cin >> intValue1;
    cin >> intValue2;
    cin >> strValue;
    cin >> doubleValue;
    
    // TODO: Erstelle Storage<int> mit dem ersten Integer und gib aus: Int storage: <value>
    
    // TODO: Mit dem zweiten Integer unter Verwendung von setValue() aktualisieren, gib aus: Updated: <value>
    
    // TODO: Erstelle Storage<std::string> mit der String-Eingabe, gib aus: String storage: <value>
    
    // TODO: Prüfe, ob der String-Speicher leer ist, gib aus: Is empty: true/false
    
    // TODO: Erstelle Pair<std::string, double> mit String und double, rufe display() auf
    
    // TODO: Erstelle Pair<int, int> mit beiden Integern, rufe display() auf
    
    return 0;
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung