Einfach verkettete Liste
-
Naja, aktuell steht da im Prinzip:
ptrlast = ptrlisteei; ptrlisteei->next = ptrlisteei;
Du willst aber erst sicherstellen, dass du vom aktuell letzten Element auf das neue letzte Element zeigst, damit du die Kette auch weiter durchgehen kannst. Und dann kannst du den Pointer, der auf das letzte Element zeigt, umbiegen und auf das neue letzte Element zeigen.
-
Okay...danke für die schnelle Hilfe. Bin jetzt gerade dabei mir einen Kopierkonstruktor für eine Liste
anzulegen. Vom Ansatz her ist es klar, was gemacht werden muss:JobList::JobList(const JobList& jbl) { //ptrfirst = jbl.ptrfirst; //ptrlast = jbl.ptrlast; //count = jbl.count; ptrfirst = ptrlast = NULL; count = 0; for (ListEI* ptr = ptrfirst; ptr != NULL; ptr = ptr->next) pushBack(ptr->job); }
Trotzdem ist mir nicht klar, warum die Zeiger auf das letzte und erste Element NULL gesetzt werden müssen.
Hätte das Argument ptrfirst, ptrlast und den counter aus den Argument übernommen. Wenn ich das mache wird
die darauffolgende For-Schleife endlos abgearbeitet??
-
In c++ nutzt man heute eigentlich
nullptr
anstelle vonNULL
. Der Unterschied istNULL
ist gleich0
undnullptr
ist ein Keyword, das einen leeren Pointer anzeigt.Wenn du die direkt im Header mit
nullptr
initialisierst, dann benötigst du das im Konstruktor nicht mehr.Wenn du
ptrfirst
undptrlast
aus dem Argument übernimmst, wo drauf zeigen die denn dann? Und, was passiert dann inpushBack
?P.S.: Wenn du es dir so nicht vorstellen kannst, man kann sowas auch mal auf Papier nachstellen, oder mit einem Debugger rein gucken, was wirklich passiert.
-
@C-Sepp: Bzgl. Kopieren erkundige dich mal nach den beiden Stichwörtern "shallow copy" und "deep copy" - dann verstehst du den Unterschied.
-
Okay...habe ich mich zu shallow copy und deep copy informiert.
Beim Debuggen habe ich dann auch erkennen können, dass in der pushback-Funktion die Verzweigung
für count==0 nicht abgearbeitet werden kann, wenn das Argument jbl.count in den Kopierkonstruktor mit
reingenommen wird. Danke!
-
Mein Programm möchte ich jetzt dahingehend erweitern, dass es ermöglicht wird, mit Iteratoren
die Job-Liste zu durchlaufen und nach bestimmten Aufträgen zu suchen. Dazu habe in der Klasse JobList
eine Klasse Iterator mit verschiedenen Operatoren und den Funktionen begin() und end() angelegt:class JobList { private: int count; struct ListEI { Job job; ListEI* next; ListEI(const Job& jb) : job(jb), next(NULL) {} }; ListEI* ptrfirst, * ptrlast; public: JobList() : ptrfirst(NULL), ptrlast(NULL), count(0) {} ~JobList(); JobList(const JobList&); //ohne Referenz Fehler "unzulässiger Kopierkonstruktor: erster Parameter darf nicht "JobList" sein ??? void pushBack(const Job&); bool popFront(Job&); int getCount(void) { return count; } void print(); class Iterator { private: ListEI* ptrit; public: Iterator(ListEI* pti = NULL) : ptrit(pti) {} Job& operator* (void) { return ptrit->job; } /*ListEI* operator++(void) { ptrit = ptrit->next; return ptrit; }*/ Iterator& operator++(void) { ptrit = ptrit->next; return *this; } bool operator== (const Iterator& it) { return ptrit == it.ptrit; } bool operator!= (const Iterator& it) { return ptrit != it.ptrit; } }; //1. Variante ListEI* begin() { return ptrfirst; } //2. Variante /*Iterator begin() const { return Iterator(ptrfirst); }*/ //2. Variante /*Iterator end() const { return Iterator(); }*/ //1. Variante ListEI* end() { return NULL; } };
Damit ist es nun möglich in der main durch die angelegte Liste zu iterieren und den jeweiligen Auftrag mit id und jobdescription über cout auszugeben:
int main() { Job job1("Teller sortieren"); Job job2("Zimmer aufräumen"); Job job3("Schlafen"); JobList myjoblist1; myjoblist1.pushBack(job1); myjoblist1.pushBack(job2); myjoblist1.pushBack(job3); myjoblist1.print(); JobList myjoblist2(myjoblist1); myjoblist2.print(); JobList::Iterator iterator = myjoblist2.begin(); for (; iterator != NULL; ++iterator) cout << *iterator << endl; }
Warum/Wie ist die Zuweisung JobList::Iterator iterator = myjoblist2.begin(); möglich? begin liefert doch eigentlich einen
Zeiger vom Typ ListEI, iterator wiederrum ist eine eigene Klasse Danke :)!
-
Bei
JobList::Iterator iterator = myjoblist2.begin();
wird implizit der
Iterator
-KonstruktorIterator(ListEI* pti)
verwendet.
Ist dasselbe wie bei der Zuweisung von z.B.std::string str = "text";
Auch hier wird der Konstruktor
std::string(const char *)
aufgerufen.
Maximal eine implizite Konvertierung ist zulässig. Aber auch verhindern läßt sich so etwas, nämlich wenn der Konstruktor mitexplicit
deklariert wird.Trotzdem wäre es besser hier, analog zu den STL-Klassen wie std:.string::begin oder std::vector<...>::begin, direkt den Iterator zurückzugeben.
Außerdem solltest du dich auch noch über "const-correctness" informieren und es einbauen - dann wäre deine Klasse konform(er) zu den STL-Klassen.
-
Okay...das ist auch gut zu wissen.
Aufgefallen ist mir auch noch, dass wenn ich das Argument des Kopierkonstruktors nicht als Referenz übergebe,
immer eine Fehlermeldung erhalte://mit const JobList& jbl keinen Fehler JobList::JobList(const JobList jbl) { ptrfirst = ptrlast = nullptr; count = 0; for (ListEI* ptr = jbl.ptrfirst; ptr != NULL; ptr = ptr->next) pushBack(ptr->job); }
Fehler:
error C2558: class "JobList": Kein Kopierkonstruktor verfügbar oder der Kopierkonstruktor is als "explicit" deklariert
error C2652: "JobList": Unzulässiger Kopierkonstruktor: erster Parameter darf nicht "JobList" seinWarum ist das so? Bei jeder anderen Funktion habe ich doch eine Wahlmöglichkeit ob ich den Parameter als Referenz oder als Kopie übergebe. Danke!
-
Das was du da schreibst ist doch der Kopierkonstruktor. Der soll also das Kopieren übernehmen. Bei deiner Argumentenliste soll der Kopierkonstruktor sich also selbst aufrufen?
-
Ich habe es mal ohne Referenz ausprobiert und da sind dann diese Fehler gekommen. Richtig...kopieren von Objekten vom Typ JobList