[gelöst]Frage zu meinem Adressbuch
-
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 AdresseDass 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:-Peine 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_INCLUDEDclassAdressen.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.
-
Die Funktionsdeklaration muss natürlich die gleiche Signatur wie die Definition haben. Bei dir ist das nicht der Fall:
// Deklaration void auslesen(int&, bool&, Adressen*); // Definition void auslesen(int& i, bool& right, Adressen* pZeiger[]) {/* ... */} // exakt das gleiche wie void auslesen(int& i, bool& right, Adressen** pZeiger) {/* ... */}
-
sorry aber irgendwie steh ich grad auf der leitung...
also die deklaration ist ja so wie dus mir grad geschrieben hast.
die definition wie die obere von den beiden. ändere ichs auf die untere kommt der gleiche fehler, aber du sagst ja auch ist exakt das gleiche, aber wo ist jetzt mein fehler?
-
fr33g schrieb:
aber wo ist jetzt mein fehler?
Steht ja in meinem Post...
Nexus schrieb:
Die Funktionsdeklaration muss natürlich die gleiche Signatur wie die Definition haben. Bei dir ist das nicht der Fall
-
aso ja kla ok danke, dann muss ich also die definition noch ändern;-)
kann mir noch einer helfen wegen dem statischen und dynamichen linken?
-
fr33g schrieb:
aso ja kla ok danke, dann muss ich also die definition noch ändern;-)
kann mir noch einer helfen wegen dem statischen und dynamichen linken?Beim statischen Linken wird sämtlicher Code irgendwelcher Bibliotheken mit in das Executable gepackt, das hat den Vorteil, dass zur Laufzeit z.B. keine zusätzlichen DLLs benötigt werden. Der Nachteil ist, dass das Executable grösser wird.
Beim dynamischen Linken ist es genau umgekehrt, das Executable wird kleiner, dafür werden aber zusätzliche DLLs benötigt, die auf dem Zielsystem vorhanden sein müssen.
-
ok dankeschön.
aber wie kann ich wählen dass mein programm statisch oder dynamisch linkt?
was muss ich da in den code schreiben also wie veranlasse ich dynamisches und statisches linken?danke schonmal