Try Catch Ausnahmebehandlung



  • Hallo zusammen,
    ich sitze gerade an eine Aufgabe, bei der ich per try catch Funktion die Eingaben in einem Taschenrechner abfangen soll.
    Es sollen keine Buchstaben eingegeben werden und die Division durch 0 soll ebenfalls nicht möglich sein bzw. soll der Benutzer darauf hingewiesen werden.
    Allerdings kommt bei meinem Code immer nur die Meldung mit den Buchstaben.
    Habe ich etwas bei der Konvertierung der Werte falsch gemacht ?

    Bitte helft mir auf die Sprünge 🙂

    #include "taschenrechner.h"
    #include "ui_taschenrechner.h"
    
    Taschenrechner::Taschenrechner(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::Taschenrechner)
    {
        ui->setupUi(this);
    }
    
    Taschenrechner::~Taschenrechner()
    {
        delete ui;
    }
    
    //der Aufzählungstyp
    enum fehler {keineZahl, istNull};
    
    //die Funktion zur Prüfung
    void Taschenrechner::check(float zahl1,float zahl2)
    {
        zahl1 = locale().toFloat(ui->lineEdit->text());
        if (ui->radioButtonDivision->isChecked() == true)
            if (zahl1 == 0)
            {
                throw istNull;
                ui->lineEdit->setFocus();
            }
    
        if (!isdigit(zahl1))
        {
            throw keineZahl;
            ui->lineEdit->setFocus();
        }
    
        zahl2 = locale().toFloat(ui->lineEdit_2->text());
        if (ui->radioButtonDivision->isChecked() == true)
            if (zahl2 == 0)
            {
                throw istNull;
                ui->lineEdit_2->setFocus();
            }
        if (!isdigit(zahl2))
        {
            throw keineZahl;
            ui->lineEdit_2->setFocus();
        }
    }
    
    //der Slot für die Schaltfläche
    float Taschenrechner::berechnen(float zahl1, float zahl2)
    {
        float ergebnis = 0;
    
        //welche Rechenoperation ist ausgewählt?
        //die Addition
        if (ui->radioButtonAddition->isChecked() == true)
            ergebnis = zahl1 + zahl2;
        //die Subtraktion
        if (ui->radioButtonSubtraktion->isChecked() == true)
            ergebnis = zahl1 - zahl2;
        //die Division
        if (ui->radioButtonDivision->isChecked() == true)
            ergebnis = zahl1 / zahl2;
        //die Multiplikation
        if (ui->radioButtonMultiplikation->isChecked() == true)
            ergebnis = zahl1 * zahl2;
    
        return (ergebnis);
    }
    
    void Taschenrechner::Ausnahmebehandlung()
    {
        float zahl1, zahl2;
        bool Ausnahme = false;
        QString ausgabe;
    
        zahl1 = locale().toFloat(ui->lineEdit->text());
        zahl2 = locale().toFloat(ui->lineEdit_2->text());
    
        try
        {
            check(zahl1, zahl2);
        }
    
        catch (fehler e)
        {
            switch (e)
            {
            case istNull:
                QMessageBox::warning(this,"Fehler","Eine Division durch 0 ist nicht moeglich.");
                Ausnahme = true;
                break;
            case keineZahl:
                QMessageBox::warning(this,"Fehler","Buchstaben sind nicht erlaubt, bitte eine Zahl eingeben.");
                Ausnahme = true;
                break;
            }
        }
    
        if (Ausnahme == false)
        {
            //die Ausgabe setzen
            ausgabe = locale().toString(berechnen(zahl1, zahl2));
            //das Ergebnis anzeigen
            ui->labelErgebnis->setText(ausgabe);
            //und auch in der LCD-Anzeige
            ui->lcdNumberErgebnis->display(ausgabe);
        }
    }
    
    void Taschenrechner::on_pushButton_clicked()
    {
        Ausnahmebehandlung();
    }
    


  • Hallo,

    bisschen aufräumen wäre gut (zahl1 kommt aus lineEdit, wird übergeben und wieder eingelesen? Was soll das?).
    Für die auf die Sprünge helfen: toFloat hat einen zweiten Parameter, mit dem du checken kannst, ob sich der übergebene String in eine Zahl konvertieren lässt. Nutze diesen Parameter. Ich weiss gar nicht, wie du dir das mit isdigit(float) vorgestellt hast. Wenn es mit dem zweiten Parameter nicht klappt: debugger! (oder am besten sofort, damit dir klar wird, was da nicht funktioniert).



  • @SGEKevin sagte in Try Catch Ausnahmebehandlung:

        if (ui->radioButtonDivision->isChecked() == true)
    

    Was ist der Returntyp von isChecked? Wenn der Typ bool ist, kannst du das so schreiben. Ansonsten würde ich empfehlen statt dessen einfach nur if (ui->radioButtonDivision->isChecked()) zu schreiben.

        if (zahl1 == 0)
        {
            throw istNull;
            ui->lineEdit->setFocus();
        }
    

    throw wirft eine exception, d.h. es wird sofort(*) zum passenden catch Block gesprungen. Das ui->lineEdit->setFocus(); dahinter wird nicht mehr ausgeführt.

    *: OK, vor dem ausführen des passenden catch Block wird noch Stack-Unwinding gemacht, aber darum geht's hier nicht.



  • Danke erstmal für die Antworten 🙂
    Ich habe den Code mal etwas überarbeitet und schlanker gestaltet.
    Allerdings ist mir immer noch nicht klar wie ich zwischen Buchstaben und 0 unterscheiden soll. Sobald der Radio-Button Division angeklickt ist, wird immer der Fehler angezeigt, dass nicht durch 0 geteilt werden darf obwohl ich auch Buchstaben eingebe.
    Was kann ich hier noch ändern ?

    #include "taschenrechner.h"
    #include "ui_taschenrechner.h"
    
    Taschenrechner::Taschenrechner(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::Taschenrechner)
    {
        ui->setupUi(this);
    }
    
    Taschenrechner::~Taschenrechner()
    {
        delete ui;
    }
    
    //der Aufzählungstyp
    enum fehler {keineZahl, istNull};
    
    //die Funktion zur Prüfung
    void Taschenrechner::checked(float zahl1, float zahl2)
    {
        bool ok;
    
        zahl1 = ui->lineEdit->text().toFloat(&ok);
        if (ui->radioButtonDivision->isChecked() == true)
            if (zahl1 == 0)
            {
                ui->lineEdit->setFocus();
                throw istNull;
            }
    
        if (ok == false)
        {
            ui->lineEdit->setFocus();
            throw keineZahl;
        }
    
        zahl2 = ui->lineEdit_2->text().toFloat(&ok);
        if (ui->radioButtonDivision->isChecked() == true)
            if (zahl2 == 0)
            {
                ui->lineEdit_2->setFocus();
                throw istNull;
            }
        if (ok == false)
        {
            ui->lineEdit_2->setFocus();
            throw keineZahl;
        }
    }
    
    //der Slot für die Schaltfläche
    void Taschenrechner::on_pushButton_clicked()
    {
        float zahl1, zahl2, ergebnis = 0;
        bool Ausnahme = false;
        QString ausgabe;
    
        zahl1 = locale().toFloat(ui->lineEdit->text());
        zahl2 = locale().toFloat(ui->lineEdit_2->text());
    
        //welche Rechenoperation ist ausgewählt?
        //die Addition
        if (ui->radioButtonAddition->isChecked() == true)
            ergebnis = zahl1 + zahl2;
        //die Subtraktion
        if (ui->radioButtonSubtraktion->isChecked() == true)
            ergebnis = zahl1 - zahl2;
        //die Division
        if (ui->radioButtonDivision->isChecked() == true)
            ergebnis = zahl1 / zahl2;
        //die Multiplikation
        if (ui->radioButtonMultiplikation->isChecked() == true)
            ergebnis = zahl1 * zahl2;
    
        try
        {
            checked(zahl1, zahl2);
        }
    
        catch (fehler e)
        {
            switch (e)
            {
            case istNull:
                QMessageBox::warning(this,"Fehler","Eine Division durch 0 ist nicht moeglich.");
                Ausnahme = true;
                break;
            case keineZahl:
                QMessageBox::warning(this,"Fehler","Buchstaben sind nicht erlaubt, bitte eine Zahl eingeben.");
                Ausnahme = true;
                break;
            }
        }
    
        if (Ausnahme == false)
        {
            //die Ausgabe setzen
            ausgabe = locale().toString(ergebnis);
            //das Ergebnis anzeigen
            ui->labelErgebnis->setText(ausgabe);
            //und auch in der LCD-Anzeige
            ui->lcdNumberErgebnis->display(ausgabe);
        }
    }
    


  • Du führst ja bisher auch zuerst immer die Rechenoperation aus und erst anschließend rufst du checked auf!

    Außerdem, wie @Jockelx schon geschrieben hast, übergibst du die beiden Zahlen als Parameter, verwendest sie aber gar nicht (sondern liest sie wieder aus den Editfeldern aus) - die Zeilen 24 und 38 sind also eigentlich überflüssig. Da du dort jedoch den Parameter ok übergibst und auswertest, solltest du stattdessen die Stringwerte als Parameter übergeben, also

    void Taschenrechner::checked(QString zahl1, QString zahl2)
    

    Und die Abfrage auf Buchstaben führst du in der falschen Reihenfolge durch (du überprüfst zuerst auf istNull).

    Und dann ist auch noch logisch falsch, daß du zahl1 auf 0 abfragst und als Fehler ansiehst (aber 0 / zahl2 ist ja erlaubt).

    Edit: Ich finde jedoch die Aufgabe (als auch die Umsetzung) hier mit Exceptions zu arbeiten nicht gut, denn hier wird die Ausnahmebehandlung für die Umsetzung der Logik benutzt (und das ist ein Anti-Pattern!).
    Hier würden auch normale Überprüfungsfunktionen (mit bool als Rückgabewert) ausreichen.



  • @SGEKevin sagte in Try Catch Ausnahmebehandlung:

    zahl1 = ui->lineEdit->text().toFloat(&ok);
    if (ui->radioButtonDivision->isChecked() == true)
        if (zahl1 == 0) ...
    if (ok == false) ...
    

    Hier hast du ein Problem. Ob toFloat fehlgeschlagen ist, ist in ok gespeichert. Du testest das aber erst NACHDEM du deinen anderen Check, in welchem zu auch zahl1 überprüfst, machst. Aber welchen Wert hat denn zahl1, wenn nicht konvertiert werden konnte? Du solltest direkt nach dem toFloat auf if (!ok) testen.


Anmelden zum Antworten