Einfach verkettete Liste



  • @C-Sepp

    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??



  • @C-Sepp

    In c++ nutzt man heute eigentlich nullptr anstelle von NULL. Der Unterschied ist NULList gleich 0 und nullptr 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 ptrfirstund ptrlast aus dem Argument übernimmst, wo drauf zeigen die denn dann? Und, was passiert dann in pushBack?

    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-Konstruktor Iterator(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 mit explicit 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" sein

    Warum 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


Log in to reply