Menu
Coddy logo textTech

Klassen-Templates

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, erlauben es Ihnen Klassentemplates, typunabhängige Klassen zu 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 aus 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

Erstellen wir ein generisches Speichersystem mithilfe von Klassenvorlagen, um einen flexiblen Container zu erstellen, der jeden Datentyp aufnehmen kann. Du organisierst deine Vorlagenklasse in einer Header-Datei und demonstrierst ihre Vielseitigkeit mit verschiedenen Typen in deinem Hauptprogramm.

Du erstellst zwei Dateien:

  • Storage.h: Definiere eine Klassenvorlage namens Storage, die als einfacher Container für einen einzelnen Wert mit einigen nützlichen Operationen dient:

    Deine Storage-Vorlage sollte Folgendes enthalten:

    • Ein privates Element zum Speichern des Werts
    • Einen Konstruktor, der einen Anfangswert übernimmt
    • 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 des Typs T entspricht, andernfalls false

    Erstelle außerdem eine Klassenvorlage namens Pair mit zwei Typparametern, die zwei zusammengehörige Werte speichert:

    • Private Elemente für den ersten und zweiten Wert (potenziell unterschiedlicher 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: Lies vier Eingaben ein (jeweils in einer eigenen Zeile):
    1. Einen ganzzahligen Wert
    2. Einen neuen ganzzahligen Wert
    3. Einen Zeichenkettenwert
    4. Einen Double-Wert

    Demonstriere deine Vorlagen wie folgt:

    1. Erstelle ein Storage<int> mit der ersten Ganzzahl und gib Folgendes aus: Int storage: <value>
    2. Aktualisiere es mit der zweiten Ganzzahl mithilfe von setValue() und gib anschließend Folgendes aus: Updated: <value>
    3. Erstelle ein Storage<std::string> mit der Zeichenketteneingabe und gib Folgendes aus: String storage: <value>
    4. Prüfe, ob der Zeichenkettenspeicher leer ist, und gib Folgendes aus: Is empty: <true/false> (gib true oder false aus)
    5. Erstelle ein Pair<std::string, double> mit dem Zeichenketten- und dem Double-Wert und rufe anschließend display() auf
    6. Erstelle ein Pair<int, int> mit beiden ganzzahligen Eingaben und rufe anschließend display() auf

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

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

Beachte, wie dieselbe Storage-Vorlage nahtlos mit Ganzzahlen und Zeichenketten funktioniert und wie Pair unterschiedliche Typen miteinander kombinieren kann. Der Compiler erzeugt für jede von dir verwendete Typkombination separate Klassendefinitionen. Denke daran, für Vorlagen mit einem einzelnen Typ die Syntax template <typename T> und für Vorlagen mit mehreren Typparametern template <typename T, typename U> zu verwenden.

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 der ersten Ganzzahl und gib aus: Int storage: <value>
    
    // TODO: Aktualisiere mit der zweiten Ganzzahl unter Verwendung von setValue(), gib aus: Updated: <value>
    
    // TODO: Erstelle Storage<std::string> mit der String-Eingabe, gib aus: String storage: <value>
    
    // TODO: Überprü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 Ganzzahlen, 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

Übe selbstständig: Online-C++-Compiler