Präfix-/Postfix-Operatoren überladen
-
Ich habe folgendes Problem zu lösen:
Schreiben Sie die drei Klassen Objekt, Liste und Iterator, die folgende Funktionalität bieten sollen: Objekt ist ein Stellvertreter für eine beliebige Klasse. Diese Klasse sollte für Testzwecke zumindest eine print Methode aufweisen, die eine eindeutig Identifizierung der Objekte ermöglicht. Liste soll Objekte in einem Array verwalten. Die Liste soll die Methoden add und insert aufweisen, die ein Objekt am Ende bzw. am Beginn der Liste einfügen können. Iterator soll einen Konstruktor haben, der den Iterator an den Beginn der Liste setzt, die Operatoren ++ und --, die zum Weiter- bzw. Zurückgehen in der Liste dienen und eine Methode obj, die das aktuelle Objekt retourniert. Unter der Annahme, dass die Liste mit den vier Objekten 'a', 'b', 'c' und 'd' gefüllt ist, soll z.B. folgendes Programmstück die angeführten Ergebnisse liefern:
Iterator it;
it.obj().print(); //Ausgabe von 'a'
it++;
it.obj().print(); //Ausgabe von 'b'
it--;
it.obj().print(); //Ausgabe von 'a'(soweit ist alles klar; der gesamte Code läuft einwandfrei)
Ändern Sie die Klasse Iterator nun so, dass die Methode obj überflüssig wird. Statt dessen soll der Operator * (Dereferenzierung) und die Operatoren ++ und -- derart überladen werden, dass das kurze Programmstück im Beispiel aus der Vorwoche nun folgendermaßen geschrieben werden kann:
Iterator it;**(*it++).print(); //Ausgabe von 'a'
(it--).print(); //Ausgabe von 'b'
(it).print(); //Ausgabe von 'a'Die Deklarationen von Objekt & Liste sehen folgendermaßen aus:
(Methode 'obj' heißt hier 'Member'; außerdem nimmt Objekt Daten vom typ int auf)const int iSize=128; //Demo-Klasse für den Listeniterator //Objekte werden in eine Liste aufgenommen class Objekt { private: int iDaten; public: //KONSTRUKTOR Objekt (int Daten=-1); //METHODEN //Gleich wie Konstruktor void setValue (int Daten); //Objektzahl ausgeben void print (); }; //Auf ihr operiert der Iterator class Liste { private: //Array an Objekten Objekt oObjekte[iSize]; //Höchster Index im Array int MaxIndex; public: //KONSTRUKTOREN //Leere Liste Liste (); //Übernimmt ein Array an Objekten & dessen Größe (Überlauf!) Liste (Objekt Objekte[iSize], int ActualSize); //METHODEN //Objekt am Ende einfügen bool addEnd (Objekt oInput); //Objekt am Beginn einfügen bool insertFirst (Objekt oInput); //Anzahl der Objekte im Array int count (); //Ein einzelnes Objekt Objekt Member (int Index); };Ich habe die entsprechenden Operatoren der Klasse Iterator nun folgendermaßen definiert:
//Setzt den Iterator ans nächste Listenelement //Beginnt von vorne wenn am Ende void Iterator::operator++ (int) { iAktuelleStelle = (iAktuelleStelle == lListe.count()-1 ? 0 : ++(iAktuelleStelle)); //return operator*(); } //Setzt den Iterator ans vorige Listenelement //Beginnt von hinten wenn am Anfang void Iterator::operator-- (int) { iAktuelleStelle = (iAktuelleStelle == 0 ? lListe.count()-1 : --(iAktuelleStelle)); //return operator*(); } //Retourniert das Objekt an der aktuelle Position Objekt Iterator::operator* () { return lListe.Member (iAktuelleStelle); }Der Operatoraufruf funktioniert problemlos, solange ich nur jeweils einen Operator verwende:
cout << "\nWert an voriger Stelle: "; (*it).print(); (it++); //richtige Ausgabe cout << "\nWert an aktueller Stelle: "; (*it).print(); //richtige AusgabeProblematisch wirds allerdings hier:
(*it++).print();Compilerfehler: 'void value not ignored as it ought to be'
Ändere ich nun die Ergebnistypen in Iterator entsprechend:
//Setzt den Iterator ans nächste Listenelement //Beginnt von vorne wenn am Ende Objekt Iterator::operator++ (int) { iAktuelleStelle = (iAktuelleStelle == lListe.count()-1 ? 0 : ++(iAktuelleStelle)); return operator*(); } //Setzt den Iterator ans vorige Listenelement //Beginnt von hinten wenn am Anfang Objekt Iterator::operator-- (int) { iAktuelleStelle = (iAktuelleStelle == 0 ? lListe.count()-1 : --(iAktuelleStelle)); return operator*(); } //Retourniert das Objekt an der aktuelle Position Objekt Iterator::operator* () { return lListe.Member (iAktuelleStelle); }Erhalte ich stattdessen die Meldung:
'no match for 'operator' in '*(&it)->Iterator::operator++(0)''*Ich habe zwar Vermutungen, wie die beiden Meldungen zu interpretieren sein könnten, aber bis jetzt keine Lösung gefunden.
Bin daher für jeden Lösungsansatz dankbar!
-
Wenn du die Rückgabe von op++ dereferenzieren willst, mußt du dort einen sinnvollen Rückgabewert angeben:
üblicherweise sehen die Inkrement-Operatoren übrigens so aus:
Typ& operator++() { //Präfix-Inkrement ++x return *this; } Typ operator++(int) { Typ tmp=*this; ++this; return tmp; }
-
Eigentlich sollte der operator++(int) eine Kopie von Iterator zurückgeben.
Der Postfix operator++ kann übrigens ruhig ein konstantes Objekt zurückgeben:
const Iterator Iterator::operator++( int ) { Iterator tmp( *this ); // ... return tmp; }Edit:
Bei deinem Dereferenzierungsoperator wäre eine konstante Referenz als Rückgabetyp besser.const Objekt& operator*() const { }grüße
-
David_pb schrieb:
Bei deinem Dereferenzierungsoperator wäre eine konstante Referenz als Rückgabetyp besser.
const Objekt& operator*() const { }grüße
Das hängt davon ab, ob die Konstanz des Iterators die Konstanz des Objekts zur Folge haben soll. Für viele (in meiner Erfahrung die meisten) Iteratoren und Smartpointer gilt das nicht. Auch für den normalen Pointer als Prototyp des Iterators ist das ja nicht der Fall. Richtig ist aber, dass der Operator selbst const sein sollte.
-
So wie Christian++ den Operator deklariert hat, hätte ein ändern des Objekts garkeinen Erfolg im Bezug auf das Objekt innerhalb des Iterators. Ansonsten soll er eben eine nicht konstante Referenz zurückgeben.
-
Wahnsinn, dieses Forum...

Herzlichen Dank an Euch alle!