Menu
Coddy logo textTech

Exception-Handling in OOP

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

Ausnahmebehandlung (Exception Handling) in C++ bietet eine strukturierte Möglichkeit, Laufzeitfehler zu erkennen und darauf zu reagieren. In der objektorientierten Programmierung integrieren sich Exceptions auf natürliche Weise in Klassenhierarchien, was es Ihnen ermöglicht, aussagekräftige Fehlertypen zu erstellen, die Kontext darüber enthalten, was schiefgelaufen ist.

Der grundlegende Mechanismus verwendet drei Schlüsselwörter: try, throw und catch. Code, der fehlschlagen könnte, kommt in einen try-Block, Fehler werden mit throw signalisiert und catch-Blöcke behandeln spezifische Ausnahmetypen:

#include <iostream>
#include <stdexcept>

class BankAccount {
    double balance;
public:
    BankAccount(double b) : balance(b) {}
    
    void withdraw(double amount) {
        if (amount > balance) {
            throw std::runtime_error("Insufficient funds");
        }
        balance -= amount;
    }
    
    double getBalance() const { return balance; }
};

int main() {
    BankAccount account(100.0);
    
    try {
        account.withdraw(150.0);
    } catch (const std::runtime_error& e) {
        std::cout << "Error: " << e.what() << "\n";
    }
    
    std::cout << "Balance: " << account.getBalance() << "\n";
}

Die C++-Standardbibliothek bietet eine Hierarchie von Exception-Klassen, die bei std::exception beginnt. Zu den gängigen abgeleiteten Klassen gehören std::runtime_error für Laufzeitprobleme und std::logic_error für Programmierfehler. Alle Standard-Exceptions bieten eine what()-Methode, die eine Fehlermeldung zurückgibt.

Wenn eine Exception geworfen wird, wird der Stack abgebaut (Stack Unwinding) – Destruktoren werden für alle lokalen Objekte aufgerufen, während das Programm nach einem passenden catch-Block sucht. Dies stellt eine ordnungsgemäße Bereinigung sicher, selbst wenn Fehler auftreten, weshalb RAII und Exception-Handling so gut zusammenarbeiten.

challenge icon

Aufgabe

Einfach

Lassen Sie uns einen sicheren Divisionsrechner bauen, der die Ausnahmebehandlung (Exception Handling) in einem objektorientierten Kontext demonstriert. Sie werden eine Calculator-Klasse erstellen, die Divisionsoperationen durchführt und aussagekräftige Ausnahmen auslöst, wenn etwas schiefgeht, und diese Ausnahmen dann in Ihrem Hauptprogramm elegant behandeln.

Sie werden Ihren Code über drei Dateien organisieren:

  • Calculator.h: Definieren Sie Ihre Calculator-Klasse, die mathematische Operationen mit ordnungsgemäßer Fehlerbehandlung durchführt.

    Ihr Calculator sollte eine Methode divide(double numerator, double denominator) haben, die das Ergebnis der Division zurückgibt. Wenn der Nenner jedoch Null ist, sollte sie eine std::runtime_error mit der Nachricht Division by zero auslösen. Wenn entweder der Zähler oder der Nenner negativ ist, sollte sie eine std::invalid_argument mit der Nachricht Negative values not allowed auslösen.

    Fügen Sie außerdem eine Methode safeSqrt(double value) hinzu, die die Quadratwurzel des Wertes zurückgibt. Wenn der Wert negativ ist, lösen Sie eine std::runtime_error mit der Nachricht Cannot compute square root of negative number aus. Sie müssen <cmath> für die sqrt-Funktion einbinden.

  • Calculator.cpp: Implementieren Sie die in Ihrer Header-Datei deklarierten Methoden. Stellen Sie sicher, dass Sie die erforderlichen Header (<stdexcept> und <cmath>) einbinden und die Bedingungen prüfen, bevor Sie die Operationen ausführen.
  • main.cpp: Lesen Sie drei Eingaben ein (jede in einer separaten Zeile):
    1. Operationstyp: entweder divide oder sqrt
    2. Erste Zahl (double)
    3. Zweite Zahl (double) — wird nur für die Division verwendet, bei sqrt ignoriert

    Erstellen Sie ein Calculator-Objekt und führen Sie die angeforderte Operation innerhalb eines try-Blocks aus. Wenn die Operation erfolgreich ist, geben Sie Result: [value] aus. Wenn eine Ausnahme abgefangen wird, geben Sie Error: [message] aus, wobei die Nachricht aus der what()-Methode der Ausnahme stammt.

    Geben Sie nach dem try-catch-Block (unabhängig davon, ob eine Ausnahme aufgetreten ist) Calculation complete aus, um zu demonstrieren, dass das Programm nach der Behandlung von Ausnahmen weiter ausgeführt wird.

Zum Beispiel bei den Eingaben divide, 10 und 2:

Result: 5
Calculation complete

Bei den Eingaben divide, 10 und 0:

Error: Division by zero
Calculation complete

Bei den Eingaben divide, -5 und 2:

Error: Negative values not allowed
Calculation complete

Bei den Eingaben sqrt, 16 und 0:

Result: 4
Calculation complete

Bei den Eingaben sqrt, -9 und 0:

Error: Cannot compute square root of negative number
Calculation complete

Beachten Sie, wie das Programm Fehler elegant handhabt, indem es Ausnahmen abfängt und aussagekräftige Nachrichten anzeigt und dann die Ausführung fortsetzt. Dieses Muster hält Ihre Fehlerbehandlung sauber und Ihre Hauptlogik auf den Erfolgsfall (Happy Path) konzentriert.

Spickzettel

Die Ausnahmebehandlung in C++ verwendet drei Schlüsselwörter: try, throw und catch. Code, der fehlschlagen könnte, wird in einen try-Block geschrieben, Fehler werden mit throw signalisiert und catch-Blöcke behandeln spezifische Ausnahmetypen:

try {
    // Code, der eine Ausnahme auslösen könnte
    account.withdraw(150.0);
} catch (const std::runtime_error& e) {
    std::cout << "Error: " << e.what() << "\n";
}

Auslösen von Ausnahmen aus Klassenmethoden:

void withdraw(double amount) {
    if (amount > balance) {
        throw std::runtime_error("Insufficient funds");
    }
    balance -= amount;
}

Die C++-Standardbibliothek bietet Ausnahmeklassen an, die auf std::exception basieren. Zu den gängigen Typen gehören:

  • std::runtime_error – für Laufzeitprobleme
  • std::logic_error – für Programmierfehler
  • std::invalid_argument – für ungültige Argumente

Alle Standardausnahmen bieten eine what()-Methode, die eine Fehlermeldung zurückgibt.

Wenn eine Ausnahme ausgelöst wird, wird der Stack abgebaut (Stack Unwinding) – Destruktoren werden für alle lokalen Objekte aufgerufen, während das Programm nach einem passenden catch-Block sucht, was eine ordnungsgemäße Bereinigung gewährleistet.

Binden Sie <stdexcept> ein, um Standard-Ausnahmeklassen zu verwenden.

Probier es selbst

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

using namespace std;

int main() {
    // Eingaben lesen
    string operation;
    double num1, num2;
    
    cin >> operation;
    cin >> num1;
    cin >> num2;
    
    // Calculator-Objekt erstellen
    Calculator calc;
    
    // TODO: Einen try-catch-Block verwenden, um die Operation auszuführen
    // - Wenn die Operation "divide" ist, rufe calc.divide(num1, num2) auf
    // - Wenn die Operation "sqrt" ist, rufe calc.safeSqrt(num1) auf
    // - Bei Erfolg "Result: " gefolgt vom Ergebnis ausgeben
    // - Exceptions abfangen und "Error: " gefolgt von der Exception-Meldung ausgeben (verwende what())
    // - Nach dem try-catch immer "Calculation complete" ausgeben
    
    
    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