Datenbank aus Objekten?



  • Hallo zusammen,
    ich möchte ein Programm schreiben, die Eine Kundendatenbank verwaltet. Jeder Kunde hat einen Datensatz mit zb. Name Umsatz, Kundenummer ect.

    Dazu habe ich mir gedacht, das ich mir eine Klasse schreibe, wo man Objekte erstellen kann mit den Variablen und den Funktionen, für die Interaktion. Das Programm soll zum Beispiel Rabatte berechnen und KundenNummern von Kunden ermitteln. Außerdem soll es aber auch neue Datensätze erstellen können. Und da komme ich einfach nicht weiter und frage mich ob ich überhaupt richtig an die Sache ran gegangen bin. Weil Wenn ich zb einen neuen Kunden hinzufügen will mit:

    Kunde& kunde = datenbank.neuerKunde( Name, Vorname, Firmenname );
    

    muss ich ja erstmal wissen, wie ich die Objekte nennen will.
    Dazu muss ich vielleicht noch sagen, das die Datenbank in einer Textdatei gespeichert werden soll.
    -> Muss ich vielleicht garnicht mehrere Objekte erstellen sondern mit Zeigern arbeiten?

    Hier ist was ich bis jetzt habe: Ich bin Anfänger und würde mich über Hilfe sehr freuen.
    main.cpp //nur ein paar Tests

    #include <iostream>
    #include <fstream>
    #include <string>
    #include "classKunde.hpp"
    
    using namespace std;
    
    int main() {
    
        kunde a;
        a.firmenName = "Musterfirma1";
        a.nachName = "Musterfrau";
        a.vorName = "Julia";
        a.jahresUmsatz = 10;
        a.kundenNummer = 12;
    
        a.getrabatt();
    
        kunde b;
        b.firmenName = "Musterfirma2";
        b.nachName = "Mustermann";
        b.vorName = "Gerd";
        b.jahresUmsatz = 10090000.89;
        b.kundenNummer = 142;
    
        b.getrabatt();
        cout << a.getKundenNummer();
    
        return 0;
    }
    

    classKunde.hpp

    # pragma once
    #include <string>
    
    using namespace std;
    
    class kunde{
    public:
        string firmenName;
        string nachName;
        string vorName;
        double jahresUmsatz;
        int kundenNummer;
        void getrabatt();
        int getKundenNummer();
    
    };
    

    classKunde.cpp

    #include "classKunde.hpp"
    #include <iostream>
    
    using namespace std;
    
    void kunde::getrabatt(){
        if (jahresUmsatz < 10000) {
            cout << "Kunde erhählt kein Rabatt" << endl;
        } else if (jahresUmsatz >= 10000 && jahresUmsatz < 20000) {
            cout << "Kunde erhählt 1% Rabatt" << endl;;
        } else if (jahresUmsatz >= 20000 && jahresUmsatz < 40000) {
            cout << "Kunde erhählt 2% Rabatt" << endl;;
        } else if (jahresUmsatz >= 40000 && jahresUmsatz < 100000) {
            cout << "Kunde erhählt 4% Rabatt" << endl;
        } else if (jahresUmsatz >= 100000) {
            cout << "Kunde erhählt 10% Rabatt" << endl;
        } else cout << "Bitte überprüfen Sie den Jahrenumsatz" << endl;
    }
    
    int kunde::getKundenNummer(){
        return kundenNummer;
    }
    

    classDatenbank.hpp

    #pragma once
    #include "classKunde.hpp"
    
    class datenbank{
    public:
        void neuerKunde(string nachName, string vorName, string Firmenname);
    };
    

    classDatenbank.cpp

    #include "classDatenbank.hpp"
    # include <string>
    
    using namespace std;
    
    void datenbank::neuerKunde(string nachName, string vorName, string Firmenname){
        kunde "???" ;
    }
    


  • Um mehrere Kunden zu verwalten, nimm

    std::vector<kunde> kunden;
    

    Und mittels

    kunde k;
    kunden.push_back(k);
    

    kannst du dann einen neuen Kunden hinzufügen.

    Du solltest auch noch einen passenden Konstruktor für den Kunden definieren.



  • So würden die Daten ja nur im Arbeitsspeicher gespeichert oder?
    Ich hab meine Frage twas unstrukturiert gestellt. Dadurch wurde glaube ich nicht wirklich klar was ich will.

    Beispiel für die Interaktion mit dem Programm:

    Hauptmenü: [L]ade Datenbank, [S]peichere Datenbank, [N]euer Kunde, Lösch[e] Kunde, S[u]che Kunde, [Q] Programm beenden
    Dateiname: kunden.txt
    Datei kunden.txt erfolgreich geladen. Datenbank enthält 10 Kunden.
    Hauptmenü: [L]ade Datenbank, [S]peichere Datenbank, [N]euer Kunde, Lösch[e] Kunde, S[u]che Kunde, [Q] Programm beenden
    >u
    Suchkriterium: [N]ame, [U]msatz >U
    Minimaler Umsatz: 1
    Maximaler Umsatz: 450
    Gefundene Kunden: 2
    Kunde 4:
    Firma: X
    Name: Mustermann
    Vorname: Max
    Umsatz: 3
    
    Kunde 6:
    Firma: Y
    Name: Müller
    Vorname: Max
    Umsatz: 60
    
    Hauptmenü: [L]ade Datenbank, [S]peichere Datenbank, [N]euer Kunde, Lösch[e]
    Kunde, S[u]che Kunde, [Q] Programm beenden
    >e
    Bitte Kundennummer eingeben: 6
    Lösche Datensatz 6, Firma Y
    Es sind jetzt 9 Kunden in der Datenbank.
    
    Hauptmenü: [L]ade Datenbank, [S]peichere Datenbank, [N]euer Kunde, Lösch[e]
    Kunde, S[u]che Kunde, [Q] Programm beenden
    >S
    Dateiname zum Speichern: kundenNeu.txt
    Datei erfolgreich gespeichert als kundenNeu.txt
    >Q
    Beende Programm.
    

    Es gibt also immer eine Textdatei mit der Datenbank. Und mit dieser Datei arbeitet das Programm.

    Wie sollte ich also die Klasse schreiben, damit ich aus den Zeilen Objekte machen kann?
    Wie würdet ihr an die Sache rangehen?



  • kaiuwe schrieb:

    Wie sollte ich also die Klasse schreiben, damit ich aus den Zeilen Objekte machen kann?
    Wie würdet ihr an die Sache rangehen?

    Das hat doch gerade jemand im Thread "Objekt in Datei speichern" (aktuell 2 Threads unter deiner Frage) jemand gefragt:
    https://www.c-plusplus.net/forum/302416

    Also: mit den Operatoren << und >>.



  • Naja das bringt mich jetzt nicht wirklich weiter.
    Ich weiß, wie man Strings in txt Datei schreibt und sie ausließt.
    Es geht mir mehr um die Klasse Kunde und wie ich beliebig viele Objekte dieser Klasse erstellen kann ohne jedesmal in der Konsole zb.

    kunde a;
        a.firmenName = "Musterfirma1";
        a.nachName = "Musterfrau";
        a.vorName = "Julia";
        a.jahresUmsatz = 10;
        a.kundenNummer = 12;
    

    schreiben zu müssen.
    Ich will nicht jeden Datensatz einzeln anlegen.
    Ich denke daher das ich mit Referenzen arbeiten muss.

    Wie gesagt, das Programm soll mit der Funktion:

    Kunde& kunde = datenbank.neuerKunde( Name, Vorname, Firmenname );
    

    umgehen können.
    Dieses Kunde& künde bedeutet doch das eine Referenz erstellt werden soll die den Typ Kunde hat oder?

    ich kenne a = &a
    aber was heißt es wenn das "&" davor steht?



  • Wie willst du denn einen Datensatz anlegen, wenn nicht einzeln?

    Was du brauchst ist z.B. so etwas:

    std::vector<Kunde> kunden
    

    In einer Funktion kannst du dann deine Kundendaten einlesen:

    Kunde neuerKunde;
    std::string name;
    // weitere Variablen für die restlichen Daten
    
    cout << "Name des Kunden: "
    cin >> name;
    
    // weitere Daten eingeben
    
    neuerKunde.name = name;
    
    // weitere Daten dem Kundenobjekt zuweisen
    datenbank.neuerKunde(neuerKunde); // Kunde in die Datenbank schreiben.
    

    Dann liest du dir den von wob angebenen Beitrag durch, damit weißt du dann wie du deine Kunden speichern und lesen kannst.

    Bezogen auf deinen Wunsch nach einer Datenbank:

    class Datenbank
    {
       public:
          void neuerKunde(const Kunde& kunde)
          void ladeAusDatei(const std::string& dateiname);
          void speicherInDatei(const std::string& dateiname);
          // weitere Funktionen
       private:
          std::vector<Kunde> kunden;
    }
    
    void Datenbank::neuerKunde(const Kunde& kunde)
    {
        kunden.push_back(kunde);
    }
    
    void Datenbank::ladeAusDatei(const std::string& dateiname)
    {
        // Code, um "kunden" aus einer Datei zu befüllen
    }
    
    void Datenbank::speicherInDatei(const std::string& dateiname);
    {
        // code, um "kunden" in eine Datei zu schreiben
    }
    

    Deine Kundenklass solltest du noch etwas überarbeiten und sinnvollerweise über geeignete Methoden auf die privaten Daten zugreifen:

    class Kunde
    {
        public:
            Kunde(const std::string& name); // ctor weitere Parameter wie Umsatz usw. noch erweitern
            std::string getName();
            // weitere Methoden
        private:
            std::string name;
            // weitere Daten
    }
    


  • verstehe ich das richtig.
    Die komplette Datenbank wäre dann ein Vektor ?
    -> Wie passt das mit dem 2. Code zusammen.
    Wie ich ihn verstanden habe:
    1. Es wird ein neues Objekt der Klasse Kunde angelegt
    2. Der Benutzer gibt die Daten ein
    3. Die eingegebenen Daten werden dem in 1. erstellten Objekt übergeben
    und jetzt.. wird dieses Objekt in den erstellten Vektor "gepusht" ?

    Wenn ich das richtig verstanden habe.
    Heißen alle Objekte gleich (also neuerKunde?) oder wie wird die Bezeichnung vergeben?
    Und wie könnte ich auf einen bestimmten Kunden zugreifen.
    Wenn ich also Kunde Müller haben will, woher weiß ich wo im Vektor dieser gespeichert ist oder geschieht der zugriff nicht über den Vektor, sonder über die Datei?

    Danke für die Hilfe 🙂



  • weil ich das gerade wieder in dem Code gesehen habe:
    Was genau bedeutet "Kunde& kunde"



  • kaiuwe schrieb:

    verstehe ich das richtig.
    Die komplette Datenbank wäre dann ein Vektor ?

    Ja.

    kaiuwe schrieb:

    -> Wie passt das mit dem 2. Code zusammen.
    Wie ich ihn verstanden habe:
    1. Es wird ein neues Objekt der Klasse Kunde angelegt
    2. Der Benutzer gibt die Daten ein
    3. Die eingegebenen Daten werden dem in 1. erstellten Objekt übergeben
    und jetzt.. wird dieses Objekt in den erstellten Vektor "gepusht" ?

    Richtig.

    kaiuwe schrieb:

    Wenn ich das richtig verstanden habe.
    Heißen alle Objekte gleich (also neuerKunde?) oder wie wird die Bezeichnung vergeben?

    Die Bezeichnung des Objektes ist ziemlich egal, dir geht es doch um die Daten.

    kaiuwe schrieb:

    Und wie könnte ich auf einen bestimmten Kunden zugreifen.
    Wenn ich also Kunde Müller haben will, woher weiß ich wo im Vektor dieser gespeichert ist oder geschieht der zugriff nicht über den Vektor, sonder über die Datei?

    Die Datei dient nur der Persistenz. Du musst den Vektor durchsuchen, bis du den richtigen Datensatz gefunden hast.

    for (auto kunde : kunden)
    {
        if (kunde.getName() == name)
        {
            // gefunden!
        }
    }
    

    Lies dir die Dokumentation von Vector durch! Möglicherweise ist auch ein anderer Containertyp (wie std::map) besser geeignet, falls du immer nach dem Namen suchst (Schlüssel!).



  • kaiuwe schrieb:

    weil ich das gerade wieder in dem Code gesehen habe:
    Was genau bedeutet "Kunde& kunde"

    Referenz auf Kunde, um eine unnötige Kopie zu vermeiden (Performance).

    Du könntest schreiben:

    void neuerKunde(Kunde kunde);
    

    dann:

    Kunde einKunde;
    
    datenbank.neuerKunde(einKunde);
    

    Das führt dann dazu, dass "einKunde" in den Parameter "kunde" kopiert wird. Durch die Referenz wird das vermieden. Das "const" zuvor stellt sicher, dass die Funktion das übergebene Objekt nicht verändert.



  • Du musst auch eine Referenz des Typ Kunde zurückgeben.

    Kunde& neuer_kunde(const Kunde& k){
        return kunden.push_back(k), kunden.back();
    }
    


  • holly321 schrieb:

    Du musst auch eine Referenz des Typ Kunde zurückgeben.

    Kunde& neuer_kunde(const Kunde& k){
        return kunden.push_back(k), kunden.back();
    }
    

    Naja, müssen tut er ja nicht, aber er könnte, wenn er denn wollte.

    Allerdings kommt mir der Code fehlerhaft vor, oder täusche ich mich?

    Kunde& neuerKunde(const Kunde& k)
    {
        kunden.push_back(k); // Kunden am Ende anhängen
        return kunden.back(); // Referenz auf das letzte Element zurückgeben
    }
    


  • [EDIT] Hat sich alles erledigt mit den vermeintlichen Laufzeitfehler (war in Wirklichkeit nur ein Breakpoint den ich ausersehen selbst gesetzt habe ;D)

    Sooo ich habe jetzt mal versucht das alles zu ordnen und zumindest mal einen Kunden zu erstellen und im Vector zu speichern. Leider kommt es zu einem Laufzeitfehler, den ich aber nicht nachvollziehen kann 😞
    Ich weiß dass die Hilfe Mühe macht und weiß sie wirklich zu schätzen 🙂
    Was ich bis jetzt habe. Was neu ist habe ich kommentiert.
    main.cpp

    #include <iostream>
    #include <fstream>
    #include <string>
    #include "main.hpp"
    #include "classKunde.hpp"
    #include "classDatenbank.hpp"
    #include "infilestream.hpp"
    
    using namespace std;
    
    void loadKundeInDatabase(const kunde& createdKunde){    /* soll eine objekt der Klasse  datenbank erstellen und
                                                             und dann mit der funktion neuerKunde den Kunden in den Vektor pushen*/
        datenbank database;
        database.neuerKunde(createdKunde);
    }
    
    void erstelleKunde(){
        string name, vorname, firmenname;
        int umsatz, kundennr;
    
        cout << "Name des Kunden: ";
        cin >> name;
    
        cout << "Vorname des Kunden: ";
        cin >> vorname;
    
        cout << "Firmenname des Kunden: ";
        cin >> firmenname;
    
        cout << "Umsatz des Kunden: ";
        cin >> umsatz;
    
        cout << "Kundennummer des Kunden: ";
        cin >> kundennr;
    
        kunde erstellterKunde;                              //muss ich ja machen, wenn ich die eingaben übergeben will, oder?
    
        erstellterKunde.setfirmenName(firmenname);
        erstellterKunde.setnachName(name);
        erstellterKunde.setvorName(vorname);
        erstellterKunde.setjahresUmsatz(umsatz);
        erstellterKunde.setkundenNummer(kundennr);
    
        loadKundeInDatabase(erstellterKunde);               /*erstellter Kunde wird wie oben beschrieben gespeichert
                                                             --> hier entsteht der Laufzeitfehler :( */
    
    }
    
    int main() {
    
        erstelleKunde();
    
        return 0;
    }
    

    classKunde.cpp

    #include "classKunde.hpp"
    #include <iostream>
    
    using namespace std;
    
    void kunde::setRabatt(){                                             //Hier frage ich mich ob ich das "this" richtig benutze
        if (jahresUmsatz < 10000) {
            this -> rabattKategorie = 0;
        } else if (jahresUmsatz >= 10000 && jahresUmsatz < 20000) {
            this -> rabattKategorie = 1;
        } else if (jahresUmsatz >= 20000 && jahresUmsatz < 40000) {
            this -> rabattKategorie = 2;
        } else if (jahresUmsatz >= 40000 && jahresUmsatz < 100000) {
            this -> rabattKategorie = 4;
        } else if (jahresUmsatz >= 100000) {
            this -> rabattKategorie = 10;
        } else
            this -> rabattKategorie = -1;
    }
    
    void kunde::setfirmenName(const string& firmenName){                  //Referenz richtig benutzt???
        this -> firmenName = firmenName;
    }
    
    void kunde::setnachName(const string& nachName){
        this -> nachName = nachName;
    }
    
    void kunde::setvorName(const string& vorName){
        this -> vorName = vorName;
    }
    
    void kunde::setjahresUmsatz(const int& jahresUmsatz){
        this -> jahresUmsatz = jahresUmsatz;
    }
    
    void kunde::setkundenNummer(const int& kundenNummer){
        this -> kundenNummer = kundenNummer;
    }
    
    int kunde::getKundenNummerByName(){
        return kundenNummer;
    }
    
    int kunde::getRabatt(){
        return rabattKategorie;
    }
    

    classDatenbank.cpp

    #include "classDatenbank.hpp"
    #include <string>
    #include <iostream>
    
    using namespace std;
    
    void datenbank::neuerKunde(const kunde& kunde){
        kunden.push_back(kunde);
    }
    
    void datenbank::getSizeOfVector(){
        cout << kunden.size() << endl;
    }
    
    void datenbank::ladeDatei(const string& dateiPfad)
    {
        // Code, um "kunden" aus einer Datei zu laden
    }
    
    void datenbank::speicherDatei(const string& dateiPfad)
    {
        // code, um "kunden" in eine Datei zu schreiben
    }
    
    void datenbank::getAll(const kunde& kunde){                 /*Hier habe ich versucht das gespeicherte Objekt 
                                                                 aus dem Vektor wieder auszugeben*/
        kunden[0].getKundenNummerByName();
    }
    


  • Ich hab gleich noch eine Frage.
    Wenn ich bei der Funktion erstelleKunde keinen Wert zurückgebe kann ich ja nichts damit anfangen.
    Dementsprechend müsste ich doch den erstelltenKunden zurück geben.
    Wie kann ich Objekte zurück geben.
    Der Code:

    kunde erstelleKunde(){
    
        kunde erstellterKunde;                              //muss ich ja machen, wenn ich die eingaben übergeben will, oder?
    
        string name, vorname, firmenname;
        int umsatz, kundennr;
    
        cout << "Name des Kunden: ";
        cin >> name;
    
        cout << "Vorname des Kunden: ";
        cin >> vorname;
    
        cout << "Firmenname des Kunden: ";
        cin >> firmenname;
    
        cout << "Umsatz des Kunden: ";
        cin >> umsatz;
    
        cout << "Kundennummer des Kunden: ";
        cin >> kundennr;
    
        erstellterKunde.setfirmenName(firmenname);
        erstellterKunde.setnachName(name);
        erstellterKunde.setvorName(vorname);
        erstellterKunde.setjahresUmsatz(umsatz);
        erstellterKunde.setkundenNummer(kundennr);
    
        return erstellterKunde;
    }
    

    funktioniert nicht.
    Fehler: Functions that differ only in their return type cannot be overloaded

    [EDIT] Hat sich erledigt. Ich habe nur vergessenen in der Header Datei void auf kunde zu wechseln.



  • Der Compiler wird wohl noch etwas mehr sagen.



  • [EDIT] Hat sich erledigt

    Ich hab gerade nochmal geguckt. Es gib keine Buildtime und auch keine Runtime Fehler.

    Ich benutze Xcode Wenn ich das Programm starte wird Zeile 20 (kunde erstellterKunde;) grün markiert und daneben steht: Thread 1: breakpoint 2.1
    In der Konsole wird (11db) angezeigt.

    Keine Ahnung was das ist.

    aktualisierter Code:

    #include <iostream>
    #include <fstream>
    #include <string>
    #include "main.hpp"
    #include "classKunde.hpp"
    #include "classDatenbank.hpp"
    #include "infilestream.hpp"
    
    using namespace std;
    
    void loadKundeInDatabase(const kunde& createdKunde){    /* soll eine objekt der Klasse  datenbank erstellen und
                                                             und dann mit der funktion neuerKunde den Kunden in den Vektor pushen*/
        datenbank database;
        database.neuerKunde(createdKunde);
    }
    
    kunde erstelleKunde(){
    
        kunde erstellterKunde;                              //muss ich ja machen, wenn ich die eingaben übergeben will, oder?
    
        string name, vorname, firmenname;
        int umsatz, kundennr;
    
        cout << "Name des Kunden: ";
        cin >> name;
    
        cout << "Vorname des Kunden: ";
        cin >> vorname;
    
        cout << "Firmenname des Kunden: ";
        cin >> firmenname;
    
        cout << "Umsatz des Kunden: ";
        cin >> umsatz;
    
        cout << "Kundennummer des Kunden: ";
        cin >> kundennr;
    
        erstellterKunde.setfirmenName(firmenname);
        erstellterKunde.setnachName(name);
        erstellterKunde.setvorName(vorname);
        erstellterKunde.setjahresUmsatz(umsatz);
        erstellterKunde.setkundenNummer(kundennr);
    
        return erstellterKunde;
        }
    
    int main() {
    
        loadKundeInDatabase(erstelleKunde());
    
        return 0;
    }
    


  • So jetzt noch eine Sinnvolle Frage.

    Nehmen wir mal an ein Kunde wird in dem Vektor "kunden" gespeichert.
    Wie findet der zugriff auf eines der Objekte statt.

    Ich möchte jetzt mit kunde.getKundenNummerByName(); die Kundennummer erhalten

    kunden[0] = kunde 1
    kunden[1] = kunde 2
    ...

    wenn ich jetzt die kundeNummer von Kunde 2 ausgeben will.
    Ich kann ja nicht auf den Vector zugreifen, weil dieser private ist.
    also: kunden[1].getKundenNummerByName geht nicht.



  • Du hast im Debugger einen Breakpoint gesetzt und das Programm wird jetzt dort angehalten. Du wirst dich wohl mal mit der XCode Dokumentation auseinandersetzen müssen.



  • Ja hab ich schon gemerkt 😉



  • kaiuwe schrieb:

    So jetzt noch eine Sinnvolle Frage.

    Nehmen wir mal an ein Kunde wird in dem Vektor "kunden" gespeichert.
    Wie findet der zugriff auf eines der Objekte statt.

    Ich möchte jetzt mit kunde.getKundenNummerByName(); die Kundennummer erhalten

    kunden[0] = kunde 1
    kunden[1] = kunde 2
    ...

    wenn ich jetzt die kundeNummer von Kunde 2 ausgeben will.
    Ich kann ja nicht auf den Vector zugreifen, weil dieser private ist.
    also: kunden[1].getKundenNummerByName geht nicht.

    Ich würde der Klasse Datenbank eine öffentliche Methode "getKundeByName" spendieren, die hat ja Zugriff auf die privaten Daten.

    Kunde getKundeByName(const std::string& name);
    

    In dieser Funktion gehst du durch alle Elemente (die Kunden) im Vector bis du den gesuchten gefunden hast und diesen gibst du zurück.

    In deinem Programm kannst du dann schreiben:

    auto gesuchterKunde = datenbank.getKundeByName("Mustermann");
    
    auto kundennummer = gesuchterKunde.getKundennummer();
    
    // oder zusammen, wenn du von dem Kunden wirklich NUR die Kundennummer brauchst
    
    auto kundennummer = datenbank.getKundeByName("Mustermann").getKundennummer();
    


  • Du weißt schon, dass die Datenbank nicht lange Bestand hat, weil am Ende der Routine der Gültigkeitsbereich der Variablen endet?

    void loadKundeInDatabase(const kunde& createdKunde){    /* soll eine objekt der Klasse  datenbank erstellen und
                                                             und dann mit der funktion neuerKunde den Kunden in den Vektor pushen*/
        datenbank database;
        database.neuerKunde(createdKunde);
    } // hier wird "database" wieder zerstört
    

Anmelden zum Antworten