Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Objekte zu einer Klasse durch Einlesen hinzufügen

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
18.07.2018, 20:52 Uhr
xLogiaa77



Hey, ich bin derzeit bei den Klassen(Konstruktoren, Methoden usw.) angekommen und nun hänge ich fest. Ich habe eine Aufgabe vor mir wo ich einen Bankkonto programmieren soll, ein ganz simples. Und zwar soll es aus einer set und get Methode bestehen, Dispo bis zu -1000 Euro und 2 Methoden um Geld einzuzahlen und abzuheben. Beim Ein und Auszahlen hänge ich gerade fest.


C++:
#include <iostream>

using namespace std;

class BankAccount{
private:
    float z;
public:
    
    float getBalance(){
        return z;
    }
    void setBalance(float zx){
        if(z<=-1000){
            z = zx;
        }
        else{
            cout << "Du bist zu weit im Dispo!" << endl;
        }
    }
    BankAccount();
    BankAccount(float);
    
    float erhoehen(float z){
        float y;
        cout << "Wie viel Geld moechten sie einzahlen?" << endl;
        cin >> y;
        return (z+y);
    }
    float abheben(float z){
            float y;
            cout << "Wie viel Geld moechten sie abheben?" << endl;
            cin >> y;
            return (z-y);
    }
    void info(float z){
        cout << "Kontostand: " << z << endl;
    }
    
};

BankAccount::BankAccount() : z(0)
{ }
BankAccount::BankAccount(float zx) : z(zx)
{ }

int main(){
    
    int x, y, z;
    BankAccount konto;
    
    cout << "Wie viel Geld haben sie auf der Bank?" << endl;
    cin >> z;
    
    cout << "Um Geld einzuzahlen, druecken sie die 1." << endl;
    cout << "Um Geld abzuheben, druecken sie die 2." << endl;
    cout << "Um den Kontostand abzufragen druecken sie die 3." << endl;
    cin >> x;
    
    switch(x){
        case 1: z = konto.erhoehen(z); break;
        case 2: z = konto.abheben(z); break;
        case 3: konto.info(z); break;
    }
    if(x==1 || x==2){
        cout << "Kontostand: " << z << endl;
    }
    else{
        return 0;
    }
    return 0;
}


So weit bin ich nun gekommen, nur weiß ich nicht wie ich das Einlesen mit der set und get Methode verknüpfen soll. Kann mir da jemand auf die Sprünge helfen? Hab auch schon viel gegooglt, aber nicht wirklich was gefunden. Wie man übrigens auch sehen kann bin ich noch nicht so richtig fit was Konstruktoren angeht, also seid nicht so hart zu mir
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
18.07.2018, 21:54 Uhr
ao

(Operator)


Hm, also, ein Konto mit einer Set-Methode hätte ich auch gern:
meinKonto.set(1000000) - klingt doch nicht schlecht, oder?

Echte Konten haben Methoden zum Einzahlen, zum Abheben und zum Abfragen des Kontostandes, aber keinen öffentlichen Setter. Worauf ich hinauswill: Lies noch mal genau nach (bzw. poste hier), was es mit dem Setter und dem Getter auf sich hat. Sollen das wirklich public-Methoden sein?

Und ich vermute stark, dass die Methoden erhoehen() und abheben() die Membervariable z des Konto-Objekts verändern sollen. So wie du es gemacht hast, verwaltest du den Kontostand in einer eigenen lokalen Variablen in main. Das ist nicht Sinn der Sache.

Und noch eins: Es ist keine gute Idee, wenn die Konto-Klasse selber ein User-Interface hat (also die Ausgabe "Wieviel Geld möchten Sie einzahlen?" und die Abfrage von der Tastatur). Besser man macht die Klasse ohne Ein-Ausgabe und programmiert das User-Interface in der main drumherum. Die Klasse wird dadurch flexibler einsetzbar, zum Beispiel in einem Programm mit grafischer Oberfläche, in der es kein cout und cin gibt.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
18.07.2018, 22:42 Uhr
xLogiaa77



Ah sorry das hätte ich aktualisieren müssen. Also ich habe später gemerkt dass da ein paar Logik und Programmierfehler drin waren. Habe jetzt einen neuen Code der auch so funktioniert wie er soll:

C++:
#include <iostream>
using namespace std;

class BankAccount{
private:
    float balance;
public:
    float getBalance(){
        return balance;
    }
    void setBalance(float xbalance){
        if(xbalance<=-1000){
            cout << "Limit ueberzogen!" << endl;
            balance = xbalance;
            return;
        }
        else{
            balance = xbalance;
        }
    }
    BankAccount();
    BankAccount(float);
    void einzahlen()
    {
        cout << "Wie viel Geld moechten sie einzahlen?" << endl;
        int einzahlen;
        cin >> einzahlen;
        setBalance( balance + einzahlen );
    }
    void auszahlen()
    {
        cout << "Wie viel Geld moechten sie auszahlen?" << endl;
        int auszahlen;
        cin >> auszahlen;
        setBalance( balance - auszahlen );
    }
};
//-------------------------------------------------------------------------------------------
BankAccount::BankAccount() : balance(-900)
{ }
BankAccount::BankAccount(float xbalance) : balance(xbalance)
{ }
//-------------------------------------------------------------------------------------------
int main(){
    int x;
    BankAccount konto;
    cout << "Kontostand: " << konto.getBalance() << endl;
    cout << "Einzahlen(1) Auszahlen(2): ";
    cin >> x;
    switch(x){
        case 1: konto.einzahlen(); break;
        case 2: konto.auszahlen(); break;
    }
    cout << "Kontostand: " << konto.getBalance() << endl;
    return 0;
}



Also bin mir nicht sicher ob ich das richtig verstanden habe aber getter und setter methoden sind dafür dass man trotz private status auf den Inhalt zugreifen kann, durch einen Umweg. Also das ist wahrscheinlich eine Funktion davon aber wofür man es ursprünglich benutzt weiß ich jetzt so nicht.

Und zum Letzten: an der Uni machen wir das noch so mit cout und cin, also nichts mit grafischer Oberfläche, also auf der Konsole. Wie meinst du es denn? Also wie könnte man es um die main funktion drumherum machen? Würde mich jetzt mal interessieren.

Dieser Post wurde am 18.07.2018 um 22:42 Uhr von xLogiaa77 editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
19.07.2018, 09:40 Uhr
ao

(Operator)


Ich meine das so:

C++:
#include <iostream>
using namespace std;

class BankAccount{
private:
    float balance;

    bool setBalance(float xbalance){
        if(xbalance<=-1000){
            //balance = xbalance;
            return false;
        }
        else{
            balance = xbalance;
            return true;
        }
    }

public:
    float getBalance(){
        return balance;
    }

    BankAccount(float startguthaben) : balance (startguthaben) {}
    
    enum ETransactionStatus
    {
        TransactionOk
        , TransactionCreditLine
        , TransactionInvalidData
    };

    ETransactionStatus einzahlen(float betrag)
    {
        if (betrag < 0)
            return TransactionInvalidData;
            
        setBalance( balance + betrag );
        return TransactionOk;
    }
    ETransactionStatus auszahlen(float betrag)
    {
        if (betrag < 0)
            return TransactionInvalidData;
            
        bool result = setBalance( balance - betrag );
        return result ? TransactionOk : TransactionCreditLine;
    }
};

//-------------------------------------------------------------------------------------------
int main(){
    int x;
    BankAccount konto (100);
    cout << "Kontostand: " << konto.getBalance() << endl;
    cout << "Einzahlen(1) Auszahlen(2): ";
    cin >> x;
    switch(x){
        case 1:
        {
            cout << "Wie viel Geld moechten sie einzahlen?" << endl;
            int betrag;
            cin >> betrag;
            
            BankAccount::ETransactionStatus status = konto.einzahlen (betrag);
            if (status != BankAccount::TransactionOk)
            {
                cout << "Fehler: " << status << endl;
            }
        }
        break;
        
        case 2:
        {
            cout << "Wie viel Geld moechten sie abheben?" << endl;
            int betrag;
            cin >> betrag;
            
            BankAccount::ETransactionStatus status = konto.auszahlen (betrag);
            if (status != BankAccount::TransactionOk)
            {
                cout << "Fehler: " << status << endl;
            }
        }
        break;
    }
    
    cout << "Kontostand: " << konto.getBalance() << endl;
    return 0;
}



Erklärungen:

1. Die Klasse BankAccount verwaltet NUR das Konto. User-Interaktion (cin/cout oder grafisch) gehört nicht zu ihren Aufgaben. Das geschieht woanders.

2. setBalance schlägt fehl, wenn durch die Transaktion der Dispo überschritten würde. Die Transaktion wird dann NICHT ausgeführt, der Kontostand ändert sich nicht.

3. setBalance ist keine public-Funktion, weil das nicht gebraucht wird. Die Public-Funktionen zum Verändern des Kontostandes sind einzahlen() und auszahlen(). Beide haben ein Argument (betrag) und geben einen Status zurück, der anzeigt, ob die Transaktion erfolgreich war.

4. Als private Helper-Methode ist setBalance aber sinnvoll, weil es mehrere Transaktionen gibt (Einzahlen und Auszahlen), die setBalance benutzen. Die erforderliche Logik muss so nur einmal programmiert werden.

5. Negative Beträge sind ungültig (Status "TransactionInvalidData").

6. Einzahlen positiver Beträge geht immer.

7. Beim Auszahlen wird die Rückgabe von setBalance geprüft, weil hierbei der Dispo überschritten werden könnte (Status "TransactionCreditLine").

8. Der Rückgabewert ist ein enum-Typ, weil so den einzelnen Fehlercodes sprechende Namen gegeben werden können.

9. Ich habe den parameterlosen Konstruktor BankAccount () entfernt. Den braucht man nicht wirklich, und jede Überladung, die man hinschreibt, ist eine mehr, die man testen muss.

10. In der main() finden alle Benutzer-Ein- und Ausgaben statt. Aus ihnen werden die erforderlichen Daten gebildet (cin >> betrag), mit denen die Public-Methoden des Kontos aufgerufen werden. Vorteil: Wenn das Programm mit einer grafischen Oberfläche neu geschrieben werden soll (*), kann die Klasse BankAccount ohne Änderungen übernommen werden. Die Beträge werden dann eben in einem Fenster oder Dialog erfasst.

(*) In Übungsaufgaben für die Uni ist das unwahrscheinlich. Im echten Leben ist solche oder ähnliche Wiederverwendung aber die Regel. Deshalb ist es wichtig, klar zu definieren, was Objekte tun und was sie nicht tun.

11. Anstelle von "Fehler: " und der Nummer könnten noch aussagekräftigere Meldungen generiert und ausgegeben werden.


Zitat:
aber getter und setter methoden sind dafür dass man trotz private status auf den Inhalt zugreifen kann

Das stimmt, aber nicht jedes Member braucht einen Getter UND Setter. Am BankAccount ist der öffentliche Getter sinnvoll, der Setter aber nicht. Der Zugriff wird anders geregelt, über Methoden wie einzahlen() und auszahlen() für Barbeträge, ueberweisen() für bargeldlose Transaktionen usw. Man kann das noch beliebig ausbauen, aber dass jemand an ein Bankterminal gehen und einfach setBalance() machen kann, das will man nicht.

Dieser Post wurde am 19.07.2018 um 10:26 Uhr von ao editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
19.07.2018, 15:06 Uhr
xLogiaa77



Okay das ist jetzt etwas fortgeschrittener, manche von den Verbesserungen kenne ich gar nicht und ist glaube ich erstmal nicht nötig. Die Aufgabe war ganz simpel gestellt (https://imgur.com/a/XhXo9Hv) und da geht es erstmal darum nur das Mindeste zu machen um noch Zeit für andere Aufgaben zu haben.

Habe Konstruktoren und getter und setter kurz vor der Aufgabe gelernt und verstehe noch nicht so ganz warum man überhaupt in public und private aufteilen sollte und was wohin sollte. Wie du jetzt meintest mit "setBalance", was war falsch dass es ihm public Bereich war?

Trotzdem für die ganzen Verbesserungsvorschläge, werde sie in Zukunft beachten.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: