[gelöst]Frage zu meinem Adressbuch


  • Administrator

    STL Container, bzw. Standardbibliothek Container:
    http://www.cplusplus.com/reference/stl/

    Zum Code:
    ... Naja ...

    Nur grob ein paar Dinge:
    - Gib ihm mehr Platz, füge Leerzeichen/Leerzeilen ein. Ein Code der atmet, ist auch gut lesbar.
    - Ein Adressbuch ist für mich irgendwie nicht das Gleiche wie eine Adresse. Ich würde somit die Klasse umbenennen. Dieser Name macht keinen Sinn.
    - Was passiert bei fehlerhaften Eingaben? Fehlerbehandlung fehlt völlig.
    - Was ist, wenn man mehrere Vornamen oder Nachnamen hat? Ich würde die Vornamen und Nachnamen auch per std::getline einlesen.
    - Mehrzeilige Adressen?
    - Handy? Fax? Geschäft Tel? 🙂

    Und gäbe noch anderes zum kritisieren. Aber ist natürlich auch ein wenig fragwürdig, wie weit ins Detail man bei einem Anfänger gehen soll 🙂

    Grüssli



  • Ok danke schonmal 🙂
    ja ich gut da werd ich dann mal probieren dass noch ein bisschen verbessern.
    ja klar fehlerbehandlung und so muss auch noch rein. wollt erst mal son kleines grundgerüst was funktioniert.
    hab den code jetzt noch so erweitert dass man beim auslesen den namen den man sucht eingibt:

    main.cpp

    #include "classAdressbuch.h"
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    int main()
    {
        const int maxSize = 40;
        bool stop = false;
        bool stop2 = false;
        for (int i=0; i<40; i++)
            {
                cout << "Wollen sie eine Adresse speichern(1)oder nicht(2)?";
                int choice;
                cin >> choice;
                if (choice == 2)
                    {
                        stop = true;
                    }
                Adressbuch *pZeiger[maxSize];
                while (stop == true)
                    {
                        cout << "Wollen sie Adressen auslesen(1) oder beenden(2)?";
                        int choice;
                        cin >> choice;
                        if (choice == 2)
                            {
                                stop2 = true;
                                break;
                            }
                        cout << "Welche Adresse wollen sie auslesen(Vorname): ";
                        string temp;
                        cin >> temp;
                        bool right;
                        for(int j=0;j<i;j++)
                            {
                                right = false;
                                if(pZeiger[j]->compareString(temp))
                                    {
                                        cout << pZeiger[j]->getVor_name() << "\n";
                                        cout << pZeiger[j]->getNach_name() << "\n";
                                        cout << pZeiger[j]->getAdresse() << "\n";
                                        cout << pZeiger[j]->getTele() << "\n";
                                        right = true;
                                        break;
                                    }
                            }
                            if(right == false)
                            {
                                cout << "Keine Übereinstimmung!\n";
                            }
                    }
                if (stop2 == true)
                    {
                        break;
                    }
                cout << "Geben sie den Vornamen ein: ";
                string vor_name;
                cin >> vor_name;
    
                cout << "Geben sie den Nachname ein: ";
                string nach_name;
                cin >> nach_name;
                cout << "Geben sie die Adresse ein: ";
                string adresse;
                cin.ignore();
                getline(cin,adresse);
                cout << "Geben sie die Telefonnummer ein: ";
                string tele;
                cin >> tele;
                pZeiger[i] = new Adressbuch;
                pZeiger[i]->setVor_name(vor_name);
                pZeiger[i]->setNach_name(nach_name);
                pZeiger[i]->setAdresse(adresse);
                pZeiger[i]->setTele(tele);
            }
        return 0;
    }
    

    classAdressbuch.h

    #include <iostream>
    #include <string>
    
    #ifndef CLASSADRESSBUCH_H_INCLUDED
    #define CLASSADRESSBUCH_H_INCLUDED
    
    class Adressbuch
    {
        public:
            void setVor_name(std::string);
            void setNach_name(std::string);
            void setAdresse(std::string);
            void setTele(std::string);
            std::string getVor_name()const{return itsVor_name;}
            std::string getNach_name()const{return itsNach_name;}
            std::string getAdresse()const{return itsAdresse;}
            std::string getTele()const{return itsTele;}
            bool compareString(std::string&)const;
        private:
            std::string itsVor_name;
            std::string itsNach_name;
            std::string itsAdresse;
            std::string itsTele;
    };
    
    #endif // CLASSADRESSBUCH_H_INCLUDED
    

    classAdressbuch.cpp

    #include "classAdressbuch.h"
    #include <iostream>
    #include <string>
    using namespace std;
    
    void Adressbuch::setVor_name(string vor_name)
    {
        itsVor_name=vor_name;
    }
    
    void Adressbuch::setNach_name(string nach_name)
    {
        itsNach_name=nach_name;
    }
    
    void Adressbuch::setAdresse(string adresse)
    {
        itsAdresse=adresse;
    }
    
    void Adressbuch::setTele(string tele)
    {
        itsTele=tele;
    }
    bool Adressbuch::compareString(string &temp)const
    {
        if(itsVor_name==temp)
            return true;
    }
    

    werd dann mal noch n paar sachen erweitern und einbauen, falls ihr noch tipps hat könnt ihr sie gerne schreiben;-)
    dass mit den stl werd ich mir au mal durchlesen;-)



  • Der Code gefällt mir so nicht. Ich persönlich würde ihn so "gestalten".

    main.cpp

    #include "classAdressbuch.h"
    #include <iostream>
    //#include <string> brauchst du nicht, vorallem nicht bei Code::Blocks
    
    using namespace std; //gewöhns dir ab
    
    int main()
    {
        const int maxSize = 40;
        int choice;
        bool stop = false;
        bool stop2 = false;
        bool right = false;
        Adressbuch *pZeiger[maxSize];
        string vorname;
    
        for(int i = 0; i < 40; i++) 
        {
            cout << "Wollen sie eine Adresse speichern(1)oder nicht(2)?";
            cin >> choice;
    
            if (choice == 2)
                stop = true;
    
            while(stop)
            {
                cout << "Wollen sie Adressen auslesen(1) oder beenden(2)?";
                cin >> choice;
    
                if (choice == 2)
                {
                    stop2 = true;
                    break;
                }
    
                cout << "Welche Adresse wollen sie auslesen(Vorname): ";
                cin >> vorname;
    
                for(int j = 0; j < i; j++)
                {
                    right = false;
                    if(pZeiger[j]->compareString(vorname))
                    {
                        cout << pZeiger[j]->getVor_name() << "\n";
                        cout << pZeiger[j]->getNach_name() << "\n";
                        cout << pZeiger[j]->getAdresse() << "\n";
                        cout << pZeiger[j]->getTele() << "\n";
                        right = true;
                        break;
                    }
                }
                if(!right)
                    cout << "Keine Übereinstimmung!\n";
            }
            if(stop2)
                break;
    
            cout << "Geben sie den Vornamen ein: ";
            string vor_name;
            cin >> vor_name;
    
            cout << "Geben sie den Nachname ein: ";
            string nach_name;
            cin >> nach_name;
            cout << "Geben sie die Adresse ein: ";
            string adresse;
            cin.ignore();
            getline(cin,adresse);
            cout << "Geben sie die Telefonnummer ein: ";
            string tele;
            cin >> tele;
            pZeiger[i] = new Adressbuch;
            pZeiger[i]->setVor_name(vor_name);
            pZeiger[i]->setNach_name(nach_name);
            pZeiger[i]->setAdresse(adresse);
            pZeiger[i]->setTele(tele);
        }
        //return 0; brauchst du nicht
    }
    

    classAdressbuch.h

    //#include <iostream> brauchst du nicht, oder benutzt du den in & out stream? ich sehe keine Eingaben/Ausgaben
    //#include <string> brauchst du nicht
    
    #ifndef CLASSADRESSBUCH_H_INCLUDED
    #define CLASSADRESSBUCH_H_INCLUDED
    
    class Adressbuch
    {
        public:
            void setVor_name(std::string);
            void setNach_name(std::string);
            void setAdresse(std::string);
            void setTele(std::string);
            std::string getVor_name() const { return itsVor_name; }
            std::string getNach_name() const { return itsNach_name; }
            std::string getAdresse() const { return itsAdresse; }
            std::string getTele() const { return itsTele; }
            bool compareString(std::string&) const;
        private:
            std::string itsVor_name;
            std::string itsNach_name;
            std::string itsAdresse;
            std::string itsTele;
    };
    
    #endif // CLASSADRESSBUCH_H_INCLUDED
    

    classAdressbuch.cpp

    #include "classAdressbuch.h"
    #include <iostream>
    #include <string>
    using namespace std;
    
    void Adressbuch::setVor_name(string vor_name)
    {
        itsVor_name = vor_name;
    }
    
    void Adressbuch::setNach_name(string nach_name)
    {
        itsNach_name = nach_name;
    }
    
    void Adressbuch::setAdresse(string adresse)
    {
        itsAdresse = adresse;
    }
    
    void Adressbuch::setTele(string tele)
    {
        itsTele = tele;
    }
    bool Adressbuch::compareString(string &temp)const
    {
        if(itsVor_name == temp)
            return true;
    }
    

    So ungefähr halt, hab jetzt mal eben drüber.
    Außerdem frage ich mich, warum du immer sowas hier machst

    if(...)
        {
            ...
        }
    //zu
    if(...)
    {
        ...
    }
    

    Mach doch die Klammer genau unter das if.
    Irgendwann kommt bestimmt mal der Zeitpunkt, in dem du verschachtelte if-Anweisungen oder Schleifen hast.
    Bei dir müsste man dann irgendwann schon nach rechts scrollen und das ist ziemlich hässlig.
    Aufjedenfall hat dein Programm immer noch den Fehler, dass es mehr als 40 Einträge zulässt.



  • ok danke.
    werd ich mir merken und ändern, vor allem noch fehlerbehandlung.
    aber mal ne frage wenn ich des using namespace std weglasse.
    wo muss dann überall des std:: dazu?
    und was ich auch noch wissen wollt gibts eg n unterschied zwischen:
    cout << "bla\n"; und
    cout << "bla" << endl;
    ???

    EDIT:
    Habs jettz so geändert wie du mirs gezeigt hast, doch er bringt mir bei der header datei lauter fehler wegen dem string???
    mach ich im header <string> rein funktionierts...


  • Mod

    FreakY<3Cpp ist da etwas übereifrig. using namespace in cpp-Dateien ist gar kein Problem. Ungünstig wird es erst, wenn du sie im Header verwendest. Ein gutes Beispiel ist dein eigenes Programm: Du hattest (in deiner ersten Version) eine Variable namens exit. Kein Problem. Es gibt in dem Header cstdlib aber auch eine Funktion std::exit. Du hättest so auch ohne Probleme cstdlib einbinden können, denn std::exit und exit sind ja zwei verschiedene Sachen. Hättest du aber in irgendeinem Header den du eingebunden hättest 'using namespace std' stehen gehabt, wären alle Sachen aus dem std-Namespace in den unbenannten Namespace gebracht worden und du hättest eine doppelte Definition von exit gehabt. Wenn jetzt jemand anderes diesen Header geschrieben hätte und du ihn nur benutzt und in diesem Header stünde ein "using namespace", dann hättest du keine Möglichkeit dieses wegzubekommen und hättest dein ganzes Programm umschreiben müssen, bloß weil jemand "using namespace" in einem Header verwendet hat. Deshalb gilt es als sehr schlechter Stil, dies zu tun.

    Da cpp-Dateien normalerweise nirgendwo inkludiert werden, kann man "using namespace" dort benutzen wie man will.

    Und warum du den Tipp bekommen hast, string nicht einzubinden, kapier ich nicht. Binde immer ALLE Header ein die du brauchst. Verlasse dich NIE darauf, dass ein bestimmter Header durch einen anderen Header schon eingebunden wird.

    Der Unterschied zwischen endl und \n ist, dass endl diesem entspricht:

    <<'\n'<<std::flush
    

    Das ist ein kleiner aber feiner Unterschied.



  • ok, jetzt mal ne kurze frage, was genau mach using namespace std;?
    was muss ich denn dann ändern falls ich es mal weglasse in einem header? also wo muss std:: überall davor?



  • Ich muss string nie inkludieren, dass ist eigentlich standard.
    Wegen dem Namespace, ich meinte nicht das es schlecht ist, nur das er es sich vielleicht abgewöhnen kann. Am Anfang hatte ich auch noch mit using namespace std rumhantiert, hatte es mir dann aber abgewöhnt und immer std:: vor allem geschrieben. Die 5 Zeichen sind jetzt auch nicht der Untergang.
    Wo du std:: davor schreiben musst, wird dir dein Compiler schon sagen.



  • FreakY<3Cpp schrieb:

    //#include <string> brauchst du nicht, vorallem nicht bei Code::Blocks

    Versteh ich nicht.
    Warum sollte man die Header nicht includen, die man braucht?! Und was hat das alles mit der IDE zu tun?!


  • Mod

    fr33g schrieb:

    ok, jetzt mal ne kurze frage, was genau mach using namespace std;?
    was muss ich denn dann ändern falls ich es mal weglasse in einem header? also wo muss std:: überall davor?

    "using namespace std" macht, dass man alles was im Namespace std steht nicht mehr mit std:: zu qualifizieren braucht. Im Namespace std stehen alle Methoden und Klassen die von der C++ Standardbibliothek angeboten werden.

    FreakY<3Cpp schrieb:

    Ich muss string nie inkludieren, dass ist eigentlich standard.

    Nein ist es nicht. Das funktioniert vielleicht bei deinem Compiler, aber sonst nicht.


  • Administrator

    SeppJ schrieb:

    fr33g schrieb:

    ok, jetzt mal ne kurze frage, was genau mach using namespace std;?
    was muss ich denn dann ändern falls ich es mal weglasse in einem header? also wo muss std:: überall davor?

    "using namespace std" macht, dass man alles was im Namespace std steht nicht mehr mit std:: zu qualifizieren braucht. Im Namespace std stehen alle Methoden und Klassen die von der C++ Standardbibliothek angeboten werden.

    Das ist ein wenig sehr einfach beschrieben. Ein meiner Meinung nach bessere Vorstellung ist die folgende:
    using namespace xxx; (xxx bewusst, weil es für alle Namensräume gilt) leert den Namensraum xxx im aktuellen Scope aus. Ab diesem Zeitpunkt, bis zum Ende von diesem Scope, hast du den ganzen Namensraum ausgeschüttet.

    Das ist mal ganz sicher nicht der Zweck eines Namensraumes, du leerst ja auch nicht Gläser auf dem Tisch aus, nachdem du sie befüllt hast.
    Zum anderen kann es zu Konflikten kommen, wobei diese Konflikte zum Teil auch etwas theoretische Konstrukte sind.

    Man sollte einfach vorsichtig damit umgehen, vor allem wenn man es immer macht, dann werden diese theoretischen Konstrukte immer wie wahrscheinlicher. Und wenn du es im Header machst, dann schüttest du die Gläser über den Köpfen anderer Entwickler aus, ohne dass die sich dagegen wehren können 😉

    Tipp:
    Man kann Namensräume auch lokal ausleeren, zum Beispiel in einer Funktion:

    #include <string>
    
    void foo()
    {
      std::string a; // hier ist std:: nötig.
    }
    
    void bar()
    {
      using namespace std;
    
      string b; // hier ist std:: nicht mehr nötig.
    }
    
    // ab hier ist aber std:: wieder nötig, da man es vorhin nur in der Funktion ausgeschüttet hat.
    
    void abc()
    {
      std::string c; // Daher hier wieder std::
    }
    

    Grüssli



  • FreakY<3Cpp schrieb:

    Ich muss string nie inkludieren, dass ist eigentlich standard.

    Und jetzt? Seit wann man Standardheader nicht mehr inkludieren? Wie gesagt kann es sein, dass deine Implementierung der Standardbibliothek bereits über andere Header std::string bekannt macht. Allerdings sind dann gewisse Dinge wie der Stream-Operator möglicherweise nicht überladen, und du hast bei deren Verwendung wieder Probleme. Also lieber gleich richtig machen, portabel bleiben und jeweils die entsprechenden Headerdateien inkludieren.



  • SeppJ schrieb:

    FreakY<3Cpp ist da etwas übereifrig. using namespace in cpp-Dateien ist gar kein Problem. Ungünstig wird es erst, wenn du sie im Header verwendest. Ein gutes Beispiel ist dein eigenes Programm: Du hattest (in deiner ersten Version) eine Variable namens exit. Kein Problem. Es gibt in dem Header cstdlib aber auch eine Funktion std::exit. Du hättest so auch ohne Probleme cstdlib einbinden können, denn std::exit und exit sind ja zwei verschiedene Sachen. Hättest du aber in irgendeinem Header den du eingebunden hättest 'using namespace std' stehen gehabt, wären alle Sachen aus dem std-Namespace in den unbenannten Namespace gebracht worden und du hättest eine doppelte Definition von exit gehabt. Wenn jetzt jemand anderes diesen Header geschrieben hätte und du ihn nur benutzt und in diesem Header stünde ein "using namespace", dann hättest du keine Möglichkeit dieses wegzubekommen und hättest dein ganzes Programm umschreiben müssen, bloß weil jemand "using namespace" in einem Header verwendet hat. Deshalb gilt es als sehr schlechter Stil, dies zu tun.

    Da cpp-Dateien normalerweise nirgendwo inkludiert werden, kann man "using namespace" dort benutzen wie man will.

    Also danke erst mal an alle für die hilfe, verstehe jetzt eg alles bis auf das using namespace im header...
    Versteh net ganz warum net und wie die mehrfachdeklaratio. Dann zustande kommen soll. Wär cool wenns nomal erklären könntsch
    dNke 🙂

    Und warum du den Tipp bekommen hast, string nicht einzubinden, kapier ich nicht. Binde immer ALLE Header ein die du brauchst. Verlasse dich NIE darauf, dass ein bestimmter Header durch einen anderen Header schon eingebunden wird.

    Der Unterschied zwischen endl und \n ist, dass endl diesem entspricht:

    <<'\n'<<std::flush
    

    Das ist ein kleiner aber feiner Unterschied.[/quote]



  • Was deinen Code weiter stark verbessern würde ist die Benutzung von Funktionen statt alles in der main() Methode zu erschlagen. Sinnvoll sind sicher Funktionen wie :
    - lies_adresse zum Einlesen eines neuen Adressbucheintrags aus der Konsole
    - zeige_adresse zur Anzeige einer ausgewählten Adresse

    Dass die Klassenbenennung etwas unglücklich ist hat ja schon jemand angesprochen, nach meinem Verständnis ist ein Adressbuch eine Sammlung von Adressen, bei dir repräsentiert die Klasse Adressbuch jedoch eine einzelne Adresse.

    Wichtiges Detailwissen ist die Übergabe von Objekten mit nicht-trivialem Konstruktor (z.B. std::string), übergibst in fast all deinen Methoden strings per value. Das bedeutet, dass für den Funktionsaufruf lokale Kopien erzeugt werden, die nach dem Funktionsauf wieder abegräumt werden müssen. In deinem Fall hat das keine Konsequenzen, da dein Programm nicht zeitkritisch ist. Normalerweise würde man die Parameter aber als const Referenzen übergeben, was die Erstellungen von temporären Kopien vermeidet.


  • Mod

    fr33g schrieb:

    Also danke erst mal an alle für die hilfe, verstehe jetzt eg alles bis auf das using namespace im header...
    Versteh net ganz warum net und wie die mehrfachdeklaratio. Dann zustande kommen soll. Wär cool wenns nomal erklären könntsch
    dNke 🙂

    Ich nehme mal an, dass du weißt, wie namespaces ungefähr funktionieren. Falls nicht, kannst (und solltest) du das in jedem Buch/Tutorial nachlesen.

    Und nun eine Metapher:
    Nimm mal an, du hast einen Roboter der Bauklötzchen anhand ihrer Farbe erkennen kann. Du kannst den Roboter programmieren und ihm sagen, welche Klötzchen er wie zusammensetzen soll, damit daraus ein Turm wird, wie du ihn haben willst. Aber wie schon gesagt, der Roboter erkennt nur Farben, du kannst also nur sowas sagen wie "Setz das grüne Klötzchen auf das blaue!". Dummerweise gibt es nicht sehr viele verschiedene Farben mit einem kurzen Namen (Namen wie "helle Mischung aus senfgrün und karminrot aber ein bisschen dunkler als silbergrau" sind halt ziemlich umständlich zum Programmieren). Doch tollerweise kann man die Klötzchen in Kisten packen und dem Roboter sagen, aus welcher Kiste er die Klötzchen Nehmen soll. Wenn man keine Kiste angibt, sucht der Roboter das Kötzchen auf dem Tisch. Das ist auch sehr praktisch, denn dann packt man die Klötchen die man oft braucht auf den Tisch und muss dann nicht mehr so viel schreiben. Man kann Programmieren: "Setz das blaue Klötzchen auf das rote Klötzchen aus der Kiste std!". Wenn man das rote Klötzchen öfters braucht kann man mit "using std::rot" den Roboter anweisen, die roten Klötzchen aus der Kiste std auf den Tisch zu packen, damit man sich beim Programmieren kürzer fassen kann. Man kann auch mit "using namespace std" die ganze Kiste std auf dem Tisch ausleeren. Das kann ganz praktisch sein, wenn man alleine Programmiert und viel aus std braucht. Wenn aber mehrere Leute mit dem Roboter arbeiten, dann haben diese vielleicht schon rote Klötzchen aus einer anderen Kiste auf den Tisch gepackt. Dann weiß der Roboter nicht, welches rote Klötzchen er nehmen soll und es funktioniert nichts mehr.

    Roboter = Compiler
    Bauklötzchen = Funktionen, Variablen, Klassen
    Farbe = Signatur. Das ist in vielen Fällen einfach der Name einer Funktion/Variable/Klasse
    Roboterprogramm = Dein Quellcode
    Turm = Der ausführbare Code, den der Compiler erzeugt
    Kisten = Namespace
    Tisch = aktueller Scope

    Alle die dies lesen, dürfen gerne helfen, die Metapher zu verbessern. Ich weiß, sie passt noch nicht 100% aber ich bekomm's gerade nicht besser hin.



  • SeppJ schrieb:

    ... denn dann packt man die Klötchen die man oft braucht ...

    Made my day! 😃

    Die Metapher passt schon ganz gut, finde ich.
    Ich hätte es mit einer Lagerhaller und verschiedenen Räumen/Etagen versucht zu erklären:

    In einer Montagehalle werden irgendwelche Sachen hergestellt, die aus Einzelteilen bestehen. Diese Einzelteile sind in Kisten verstaut, die in verschiedenen Schränken in verschiedenen Räumen stehen. Die Stückliste des Bauplans beschreibt die benötigten Bauteile folgendermassen:
    Raum::Schrank::Kiste::Bauteil (Bauteil weil in sich einer Kiste unterschiedliche Bauteile befinden). Wenn also das Bauteil X::Y::Z::BT benötigt wird geht der Monteur in den Raum X zu Schrank Y und nimmt aus der Kiste Y das Bauteil BT. Der Monteur braucht zur Identifikation eines Bauteils also immer 4 Angaben. Weil er sich aber die Lauferei sparen möchte nimmt er die komplette Kiste mit zu seiner Werkbank (using namespace X::Y::Z), wenn er jetzt Bauteil BT braucht greift er einfach in die Kiste und nimmt das Teil heraus.
    Dummerweise gibt es aber noch ein anderes Bauteil BT, das mit dem ersten nichts zu tun hat und in sich in der Kiste A::B::C befindet (also A::B::C::BT heisst). Wenn der Monteur jetzt nur den Namen des Bauteils (BT) benutzt, weiss er nicht, ober er in Kiste A::B::C oder X::Y::Z suchen soll, daher muss das Bauteil mit seinem vollständigen Namen benannt werden.

    Naja, ist im Groben genau das, was sepp schon erklärt hat, weiss nicht, ob´s unbedingt besser ist.



  • SeppJ schrieb:

    ...

    DocShoe schrieb:

    ...

    Hm. Man hätte auch die Bauklötzchen und Bob the Builder mit seinen Kisten und Kästen beiseite lassen können und das ganze mit namespaces und dem Compiler erklären können - da hätte sich schnell ein simples Beispiel gefunden das nicht komplizierter oder schwererverständlich oder aufwändiger zu beschreiben gewesen wäre. Im Gegenteil, man hätte sich sogar die Legende (Klötzchen = Bezeichner, BobTheBuilder = Compiler...) sparen können 😉



  • DocShoe schrieb:

    Was deinen Code weiter stark verbessern würde ist die Benutzung von Funktionen statt alles in der main() Methode zu erschlagen. Sinnvoll sind sicher Funktionen wie :
    - lies_adresse zum Einlesen eines neuen Adressbucheintrags aus der Konsole
    - zeige_adresse zur Anzeige einer ausgewählten Adresse

    Dass die Klassenbenennung etwas unglücklich ist hat ja schon jemand angesprochen, nach meinem Verständnis ist ein Adressbuch eine Sammlung von Adressen, bei dir repräsentiert die Klasse Adressbuch jedoch eine einzelne Adresse.

    Wichtiges Detailwissen ist die Übergabe von Objekten mit nicht-trivialem Konstruktor (z.B. std::string), übergibst in fast all deinen Methoden strings per value. Das bedeutet, dass für den Funktionsaufruf lokale Kopien erzeugt werden, die nach dem Funktionsauf wieder abegräumt werden müssen. In deinem Fall hat das keine Konsequenzen, da dein Programm nicht zeitkritisch ist. Normalerweis
    e würde man die Parameter aber als const Referenzen übergeben, was die Erstellungen von temporären Kopien vermeidet.

    mhh was sind denn nich trivale objekte?

    Danke für eure metapher habs gecheckt;-)
    danke auf jeden fall mal für eure mühe=)



  • Objekte mit nicht-trivialem Kopierkonstruktor sind z.B. Objekte, bei denen die einzelnen Attribute nicht bitweise kopiert werden können. std::string gehört auch dazu, weil:

    Ein std::string verwaltet den dynamischen Speicher zur Speicherung der Zeichenkette selbst, nehmen wir mal an es sei ein char*. Im Destruktor des std::string gibt das zerstörende Objekt diesen Speicher wieder frei, um kein Speicherleck zu hinterlassen.
    Würde der Kopierkonstruktor von std::string alle Elemente bitweise kopieren hätte man zwei std::string Objekte, die auf den gleichen Speicherbereich zeigen (da der char* bitweise kopiert wurde). Wenn eins der beiden Objekte zerstört wird (z.B. weil sein scope ungültig wird), dann gibt es den Speicher wieder frei. Unglücklicherweise weiss das zweite string Objekt davon nichts und ist im festen Glauben, sein char* sei weiterhin gültig. Jede Operation auf dem zweiten string führt zu undefiniertem Verhalten, da der Zeiger tatsächlich in´s Nirvana zeigt.

    Um diese Problem zu umgehen muss der Kopierkonstruktor (und auch der Zuweisungsoperator) eine Kopie des Speicherbereichs des Quellobjekts anlegen und den Inhalt des ersten strings dorthin kopieren. Daher ist der Kopierkonstruktor nicht trivial und Objekte dieses Typs sollten normalerweise als const-Referenzen übergeben werden, wenn sie in der aufgerufenen Funktion/Methode nicht verändert werden.



  • ok danke dann ist mir jetzt eg alles klar:)
    trival ist ja dann logischerweise das gegenteil:-P

    eine frage hätt ich noch die ich schon länger mal wissen wollte...
    was heißt eg genau dynamisches linken und statisches linken und wie unterscheide ich es? also wie ist zum beispiel mein programm adressbuch?
    und wie änder ich es?

    danke schonmal



  • So ich hab jetzt mal noch die Werte als Referenz übergeben,den Klassennamen angepasst und wollte noch eine Funktion für auslesen und einlesen machen.
    Jedoch bekomme ich immer zwei compiler fehler und weiß net so wirklich weiter,vielleicht könnt ihr mir ja nochmal helfen=):

    main.cpp

    #include "classAdressen.h"
    #include <iostream>
    #include <string>
    using namespace std;
    
    void auslesen(int&, bool&, Adressen*);
    void einlesen(int&,Adressen*);
    
    int main()
    {
        const int maxSize = 40;
        int choice;
        bool stop = false;
        bool stop2 = false;
        bool right = false;
        Adressen *pZeiger[maxSize];
        //string vorname;
    
        for (int i = 0; i < 40; i++)
        {
            marke:;
            cout << "Wollen sie eine Adresse speichern(1)oder nicht(2)?";
            cin >> choice;
    
            if (choice == 2)
                stop = true;
            else if( (choice != 2) && (choice != 1) )
            {
                cout << "Falsche Eingabe\n";
                goto marke;
            }
    
            while (stop == true)
            {
                marke2:;
                cout << "Wollen sie Adressen auslesen(1) oder beenden(2)?";
                cin >> choice;
    
                if (choice == 2)
                {
                    stop2 = true;
                    break;
                }
                else if( (choice != 2) && (choice != 1) )
                {
                    cout << "Falsche Eingabe\n";
                    goto marke2;
                }
    
                auslesen(i,right,pZeiger[maxSize]);
                /*cout << "Welche Adresse wollen sie auslesen(Vorname): ";
                cin >> vorname;
    
                for(int j = 0; j < i; j++)
                {
                    right = false;
                    if(pZeiger[j]->compareString(vorname))
                    {
                        cout << pZeiger[j]->getVor_name() << "\n";
                        cout << pZeiger[j]->getNach_name() << "\n";
                        cout << pZeiger[j]->getAdresse() << "\n";
                        cout << pZeiger[j]->getTele() << "\n";
                        right = true;
                        break;
                    }
                }
                if(!right)
                    cout << "Keine Übereinstimmung!\n";*/
    
            }
            if (stop2 == true)
                break;
    
            einlesen(i,pZeiger[maxSize]);
            /*cout << "Geben sie den Vornamen ein: ";
            string vor_name;
            cin >> vor_name;
    
            cout << "Geben sie den Nachname ein: ";
            string nach_name;
            cin >> nach_name;
    
            cout << "Geben sie die Adresse ein: ";
            string adresse;
            cin.ignore();
            getline(cin,adresse);
    
            cout << "Geben sie die Telefonnummer ein: ";
            string tele;
            cin >> tele;
    
            pZeiger[i] = new Adressen();
            pZeiger[i]->setVor_name(vor_name);
            pZeiger[i]->setNach_name(nach_name);
            pZeiger[i]->setAdresse(adresse);
            pZeiger[i]->setTele(tele);*/
        }
    
    }
    
    void auslesen(int& i, bool& right, Adressen* pZeiger[])
    {
        string vorname;
        cout << "Welche Adresse wollen sie auslesen(Vorname): ";
        cin >> vorname;
    
        for(int j = 0; j < i; j++)
        {
            right = false;
            if(pZeiger[j]->compareString(vorname))
            {
                cout << pZeiger[j]->getVor_name() << "\n";
                cout << pZeiger[j]->getNach_name() << "\n";
                cout << pZeiger[j]->getAdresse() << "\n";
                cout << pZeiger[j]->getTele() << "\n";
                right = true;
                break;
            }
        }
        if(!right)
        cout << "Keine Übereinstimmung!\n";
    }
    
    void einlesen(int& i,Adressen *pZeiger[])
    {
        cout << "Geben sie den Vornamen ein: ";
        string vor_name;
        cin >> vor_name;
    
        cout << "Geben sie den Nachname ein: ";
        string nach_name;
        cin >> nach_name;
    
        cout << "Geben sie die Adresse ein: ";
        string adresse;
        cin.ignore();
        getline(cin,adresse);
    
        cout << "Geben sie die Telefonnummer ein: ";
        string tele;
        cin >> tele;
    
        pZeiger[i] = new Adressen();
        pZeiger[i]->setVor_name(vor_name);
        pZeiger[i]->setNach_name(nach_name);
        pZeiger[i]->setAdresse(adresse);
        pZeiger[i]->setTele(tele);
    }
    

    classAdressen.h

    #include <string>
    
    #ifndef CLASSADRESSEN_H_INCLUDED
    #define CLASSADRESSEN_H_INCLUDED
    
    class Adressen
    {
        public:
            void setVor_name(std::string&);
            void setNach_name(std::string&);
            void setAdresse(std::string&);
            void setTele(std::string&);
            std::string getVor_name()const{return itsVor_name;}
            std::string getNach_name()const{return itsNach_name;}
            std::string getAdresse()const{return itsAdresse;}
            std::string getTele()const{return itsTele;}
            bool compareString(std::string&)const;
    
        private:
            std::string itsVor_name;
            std::string itsNach_name;
            std::string itsAdresse;
            std::string itsTele;
    };
    
    #endif // CLASSADRESSEN_H_INCLUDED
    

    classAdressen.cpp

    #include "classAdressen.h"
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    void Adressen::setVor_name(string &vor_name)
    {
        itsVor_name=vor_name;
    }
    
    void Adressen::setNach_name(string &nach_name)
    {
        itsNach_name=nach_name;
    }
    
    void Adressen::setAdresse(string &adresse)
    {
        itsAdresse=adresse;
    }
    
    void Adressen::setTele(string &tele)
    {
        itsTele=tele;
    }
    bool Adressen::compareString(string &temp)const
    {
        if(itsVor_name==temp)
            return true;
    }
    

    Also und zwar bringt er in Zeile 51: undefindet reference to auslesen(int&,bool&,Adressen*)
    und in zeile 75 undefinded reference to einlesen(int&,Adressen*)

    So wenn ich den Fehler noch behoben habe und das Programm wieder läuft wär für mich dieses Programm eg abgeschlossen dann könnt ich mir mal was neues überlegen und von anfang an besser vorgehen.


Anmelden zum Antworten