Menu
Coddy logo textTech

Enum-Klassen & starke Typisierung

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

C++11 führte enum classes (auch bereichsbezogene Enumerationen genannt) ein, um die Schwächen traditioneller C-ähnlicher Enums zu beheben. Sie bieten eine stärkere Typsicherheit und verhindern die versehentliche missbräuchliche Verwendung von Enumerationswerten.

Traditionelle Enums haben Probleme: Ihre Werte gelangen in den umgebenden Gültigkeitsbereich und werden implizit in Integer konvertiert, was zu schwer erkennbaren Bugs führt:

// Traditionelles enum - problematisch
enum Color { Red, Green, Blue };
enum TrafficLight { Red, Yellow, Green };  // Fehler! Red und Green bereits definiert

int x = Red;  // Konvertiert implizit zu int (0)
if (Red == 0) { }  // Kompiliert - Vergleich von enum mit int

Enum-Klassen lösen diese Probleme, indem sie Werte in einen Gültigkeitsbereich einschließen und implizite Konvertierungen verhindern:

enum class Color { Red, Green, Blue };
enum class TrafficLight { Red, Yellow, Green };  // OK - kein Konflikt

Color c = Color::Red;      // Muss Scope-Operator verwenden
// int x = c;              // Fehler! Keine implizite Konvertierung
int x = static_cast<int>(c);  // Explizite Konvertierung erforderlich

// if (c == 0) { }         // Fehler! Kann nicht mit int verglichen werden
if (c == Color::Red) { }   // OK - Vergleich gleicher Typen

Du kannst auch den zugrunde liegenden Typ zur Speichersteuerung angeben:

enum class Status : uint8_t {
    Inactive = 0,
    Active = 1,
    Pending = 2
};

Enum-Klassen lassen sich gut in OOP-Designs integrieren, machen den Code lesbarer und erkennen Typfehler bereits zur Kompilierzeit statt erst zur Laufzeit.

challenge icon

Aufgabe

Einfach

Wir erstellen ein Aufgabenprioritätssystem, das Enum-Klassen verwendet, um verschiedene Prioritätsstufen und Aufgabenstatus darzustellen. Dies veranschaulicht, wie Enum-Klassen Typsicherheit bieten und die Arten von Fehlern verhindern, die bei herkömmlichen Enums auftreten.

Du organisierst deinen Code über drei Dateien:

  • TaskTypes.h: Definiere deine Enum-Klassen für das Aufgabensystem.

    Erstelle eine Priority-Enum-Klasse mit den Werten: Low, Medium, High und Critical. Lege int als zugrunde liegenden Typ fest, mit den Werten 1, 2, 3 beziehungsweise 4.

    Erstelle eine Status-Enum-Klasse mit den Werten: Pending, InProgress und Completed.

    Stelle zwei Hilfsfunktionen bereit:

    • priorityToString(Priority p): gibt die Priorität als Zeichenkette zurück ("Low", "Medium", "High" oder "Critical")
    • statusToString(Status s): gibt den Status als Zeichenkette zurück ("Pending", "InProgress" oder "Completed")
  • Task.h: Definiere eine Task-Klasse, die deine Enum-Klassen verwendet.

    Deine Task soll einen Namen (Zeichenkette), eine Priority und einen Status speichern. Der Konstruktor soll einen Namen und eine Priorität übernehmen, wobei der Status standardmäßig auf Status::Pending gesetzt wird.

    Implementiere diese Methoden:

    • setStatus(Status s): aktualisiert den Status der Aufgabe
    • getPriorityValue(): gibt den zugrunde liegenden Ganzzahlwert der Priorität mithilfe von static_cast zurück
    • display(): gibt die Aufgabe im folgenden Format aus: [name] - Priority: [priority] (Value: [value]) - Status: [status]
  • main.cpp: Lies drei Eingaben ein:
    1. Aufgabenname (Zeichenkette)
    2. Prioritätsstufe als Ganzzahl (1=Low, 2=Medium, 3=High, 4=Critical)
    3. Status als Ganzzahl (0=Pending, 1=InProgress, 2=Completed)

    Erstelle eine Task mit dem angegebenen Namen und der angegebenen Priorität (wandle die Ganzzahl mithilfe von Priority in den entsprechenden static_cast-Enum-Wert um). Setze anschließend den Status basierend auf der dritten Eingabe. Rufe schließlich display() auf, um die Aufgabendetails anzuzeigen.

Bei den Eingaben Fix bug, 3 und 1 ergibt sich beispielsweise:

Fix bug - Priority: High (Value: 3) - Status: InProgress

Bei den Eingaben Write docs, 1 und 2 ergibt sich:

Write docs - Priority: Low (Value: 1) - Status: Completed

Bei den Eingaben Deploy app, 4 und 0 ergibt sich:

Deploy app - Priority: Critical (Value: 4) - Status: Pending

Beachte, wie die Enum-Klassen die Werte für Priorität und Status vollständig getrennt halten. Du kannst nicht versehentlich eine Priority mit einem Status vergleichen oder das eine dem anderen zuweisen. Das explizite static_cast, das für die Umwandlung zwischen Ganzzahlen und Enum-Werten erforderlich ist, macht die Absicht des Codes deutlich und verhindert subtile Fehler.

Probier es selbst

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

using namespace std;

int main() {
    // Eingaben lesen
    string taskName;
    int priorityInt;
    int statusInt;
    
    getline(cin, taskName);
    cin >> priorityInt;
    cin >> statusInt;
    
    // TODO: Erstelle einen Task mit dem gegebenen Namen und der Priorität
    // Verwende static_cast, um priorityInt in das Priority-Enum umzuwandeln
    
    // TODO: Setze den Status des Tasks basierend auf statusInt
    // Verwende static_cast, um statusInt in das Status-Enum umzuwandeln
    
    // TODO: Rufe display() auf, um die Task-Details anzuzeigen
    
    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