Verkettete Listen



  • Hallo,
    in meinem Buch wird das Thema Verkettete Listen OO verdeutlicht. Hier mal die Klassendefinitionen:

    class Knoten { 
    public: 
       Knoten() {} 
       virtual ~Knoten() {} 
       virtual Knoten* einfuegen( Daten* d ) = 0; 
       virtual void anzeigen() = 0; 
    }; 
    class AllgemeinerKnoten : public Knoten { 
    private: 
       Daten* daten; 
       Knoten* next; 
    public: 
       // Konstruktor 
       AllgemeinerKnoten( Daten* d, Knoten* n ): 
                                     daten(d), next(n) { 
       // Zu Debug- bzw. Verständniszwecken ggf. entfernen 
       cout << "Objekt [AllgemeinerKnoten] erzeugt\n"; 
       } 
       // Destruktor 
       ~AllgemeinerKnoten() { 
          delete next; 
          delete daten; 
       } 
       // Implizit virtual 
       Knoten* einfuegen( Daten* d ); 
       // Implizit virtual 
       void anzeigen(); 
    };
    
    class EndKnoten : public Knoten { 
    public: 
       EndKnoten() { 
       // Zu Debug- bzw. Verständniszwecken ggf. entfernen 
       cout << "Objekt [EndKnoten] erzeugt\n"; 
       } 
       ~EndKnoten() {} 
       // Implizit virtual 
       Knoten* einfuegen( Daten* d ); 
       // Implizit virtual 
       void anzeigen() { }; 
    }; 
    
    private: 
       // ... zeigt immer auf das erste Element 
       Knoten* next; 
    public: 
       // Konstruktor 
       AnfangsKnoten() { 
          // ... gleich auch einen Endknoten erzeugen 
          next = new EndKnoten; 
          // Zu Debug- bzw. Verständniszwecken ggf. entfernen 
          cout << "Objekt [AnfangsKnoten] erzeugt\n"; 
       } 
       ~AnfangsKnoten() {}
       // Implizit virtual 
       Knoten* einfuegen( Daten* d ); 
       // Implizit virtual 
       void anzeigen(); 
    }; 
    class Liste { 
    private: 
       AnfangsKnoten *anfang; 
    public: 
       // Bei Anlegen gleich ein Objekt "Anfangsknoten" erzeugen 
       // Der Konstruktor von "AnfangsKnoten" erzeugt wiederum 
       // ein Objekt "EndKnoten", auf das dieser gleich zeigt. 
       Liste() { anfang = new AnfangsKnoten; } 
       ~Liste() { delete anfang; } 
       void einfuegen( Daten* d ) { 
          anfang->einfuegen(d); 
       } 
       void alles_anzeigen() { 
          anfang->anzeigen(); 
       } 
    };
    

    Die Methoden habe ich jetzt mal weggelassen.
    Das ganze Funktioniert im Prinzip so:
    Anfangsknoten<->AllgemeinerKnoten<->---<->AllgemeinerKnoten<->Endknoten

    Mein Problem ist jetzt Der Destruktur von Alg.Knoten löscht jeweils den nächsten, auf den er zeigt. Also der Letzte AlgKnoten den Endknoten etc. Der Anfangsknoten wird von der Liste gelöscht. Nur wie wird der erste allgemeine Knoten in der Liste gelöscht?

    Viele Grüße



  • da fehlt dem Anfangsknoten wohl auch ein delete nex; im Destruktor.



  • Gut hätte ich auch gesagt. Der Fehler wird aber auch in den folgenden Kapiteln, die darauf aufbauen nicht behoben.

    Dann noch eine Frage in einem späteren Kapitel wird an dem Beispiel das Arbeiten mit Templates verdeutlicht.
    Da werden alle Knoten Klassen mit Templates ausgestattet. Aber hätte man nicht einfach die Klasse Daten, in der die Werte gespeichert sind mit Templates ausstatten können?



  • Tom2 schrieb:

    Aber hätte man nicht einfach die Klasse Daten, in der die Werte gespeichert sind mit Templates ausstatten können?

    Hätte man, aber dazu hätte man dann immernoch das Klassentemplate Daten überall mit rumschleppen müssen, jedesmal ein neues Daten<X> erstellen müssen bevor man es in die Liste hängt usw. Dann lieber gleich die ganze Liste zum Template machen und die Elemente direkt da reinhängen.



  • Dazu noch eine Frage zu den Templates. Dort steht so ungefähr folgender Code:

    template <class T> 
    void input( Liste<T>& data ) { 
         input_func( data ); 
    } 
    ...
    void input_func( Liste<Temperatur>& tempList ) { 
    ...
    void input_func( Liste<Daten>& datenList ) { 
    ...
    

    Ist die Funktion input nicht total sinnlos? Man könnte doch gleich input_func in func umbenennen. Das hätte doch durch die Überladung genau den gleichen Effekt. Zumal die Überladung in func ohnehin genutzt wird.



  • Kann mir da keiner weiterhelfen, und sagen, ob ich richtig lag?



  • Wenn in deinen weggeschnittenen Stellen nicht zusätzliche Informationen versteckt waren: ja.

    Ansonsten:
    Geht es in dem Kapitel um Refactoring und wie man trotz neuer Methodennamen auch noch die alte API supported?
    Handelt es sich da um freie Funktionen oder Methoden einer Klasse?
    Ist da irgendwas abgeleitet und in der Basisklasse war input_func virtual?
    Oder IST das eine Basisklasse und in der Klassendefinition ist input_func als virtual deklariert?
    Welches Buch ist das?



  • Hier komplett:

    // main.cpp 
    #include "daten.h" 
    #include "temperatur.h" 
    #include "lliste.h" 
    void input_func( Liste<Temperatur>& tempList ); 
    void input_func( Liste<Daten>& datenList ); 
    template <class T> void input( Liste<T>& data ); 
    int main( void ) { 
       // Instantiierung 
       Liste<Temperatur> elemente1; 
       Liste<Daten> elemente2; 
       input(elemente1);   // Liste<Temperatur> 
       input(elemente2);   // Liste<Daten> 
       elemente1.alles_anzeigen(); 
       elemente2.alles_anzeigen(); 
       return 0; 
    } 
    // Funktion zum Einlesen der Eigenschaften für Temperatur 
    void input_func( Liste<Temperatur>& tempList ) { 
       Temperatur* daten; 
       int grad; 
       char monat[20]; 
       for(;;) { 
          cout << "Monat eingeben : "; 
          if( (!(cin >> monat)) ) 
             strcpy( monat, "keine Angabe");
          cout << "Temperatur eingeben (99=Ende) : "; 
          if( (!(cin >> grad)) || grad == 99 ) 
             break; // Ende 
          daten = new Temperatur(grad, monat); 
          tempList.einfuegen(daten); 
       } 
    } 
    // Funktion zum Einlesen der Eigenschaften für Daten 
    void input_func( Liste<Daten>& datenList ) { 
       Daten* daten; 
       int iwert; 
       for(;;) { 
          cout << "Wert eingeben (0=Ende) : "; 
          if( (!(cin >> iwert)) || iwert == 0 ) 
             break; // Ende 
          daten = new Daten(iwert); 
          datenList.einfuegen(daten); 
       } 
    } 
    // Funktions-Template 
    template <class T> 
    void input( Liste<T>& data ) { 
         input_func( data ); 
    }
    

    Buch: C++ von A bis Z


Anmelden zum Antworten