[gelöst] Überladen des ++ Operators (Prä-/Postfix)
-
Hallo!
Meine Frage bezieht sich auf ein Bauspielprogramm aus dem Buch "C++ von A-Z" von Jürgen Wolf. Ich weiss das sich jetzt einigen hier die Zehennägel rumkrempeln werden und die Hutschnur hochgeht, aber zu meiner Verteidigung muss ich sagen, dass ich das Buch unwissenderweise vor 1 Jahr gekauft habe ohne hier ins Forum zu schauen. Mein Plan war eigentlich in den aktuellen Semesterferien einen guten C++ Einblick zu erhalten und da mir der Stroustrup doch etwas zu schnell startete fiel die Wahl auf den Schinken aus dem Galileo-Verlag der seit dem Kauf unberührt im Regal stand. Wie dem auch sei, hier ist erst einmal das Listing:
// complex5.cpp #include <iostream> using namespace std; class myComplex { private: double _real; double _image; public: myComplex( double val1=0.0, double val2=0.0 ) { _real = val1; _image = val2; } void print_Complex( ) { cout << _real << "+" << _image << "\n"; } // Präfix-Operator ++ überladen myComplex& operator++() { _real++; _image++; return *this; } // Postfix-Operator ++ überladen myComplex& operator++(int) { static myComplex tmp(*this); _real++; _image++; return tmp; } }; int main( void ) { myComplex val1(1.1, 2.2); ++val1; cout << "Wert von val1: "; val1.print_Complex( ); val1++; cout << "Wert von val1: "; val1++.print_Complex( ); cout << "Wert von val1: "; val1.print_Complex( ); return 0; }
Das Problem ist nun folgendes, eigentlich sind es sogar 2 Probleme, erstens lautet die Ausgabe des Programms laut Buch so:
Wert von val1: 2.1+3.2
Wert von val1: 3.1+4.2
Wert von val1: 4.1+5.2Nachdem kompilieren des Quelltextes erscheint aber folgende Ausgabe:
Wert von val1: 2.1+3.2
Wert von val1: 2.1+3.2
Wert von val1: 4.1+5.2Es ist zwar nicht unbedingt hilfreich, es sei aber an dieser Stelle erwähnt das ich unter Xubuntu 11.04 arbeite und mit gcc/c++ kompiliere.
Das zweite Problem wäre warum der Autor den Adressoperator an dieser Stelle myComplex*&** operator++()* verwendet, komischerweise wurde das bei den anderen Funktionen zur Operator-Überladung in dem Kapitel nicht so gemacht und lässt sich ohne den Adressoperator auch problemlos kompilieren. Der Rückgabewert der Funktion ist doch auch keine Adresse sondern ein schnödes Objekt, oder?
Ziemlich viel für den ersten Beitrag aber ich hoffe ihr könnte mir weiterhelfen.
-
Das ist kein Adressoperator, sondern eine Referenz und das was Herr Wolf da in der Funktion tut ist, sofern es kein Lehrbeispiel zu static sein soll, eine Sauerei, auch wenn es technisch gesehen ein richtiges Programm ist. Es verhindert aktiv Optimierungen und Parallelisierbarkeit und bietet keine Vorteile.
Dass das Ergebnis im Buch nicht stimmt, rundet das Gesamtbild ab.
Wie das mit dem Überladen von Operatoren gut und richtig geht, erfährst du hier:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-232010.html
-
Also es ist schonmal kein Bsp. was die Verwendung von static erläutern soll
Referenzen verwirren mich immer noch leicht, unter C erhalte ich ja die Adresse wenn ich "&x" verwende, deshalb verdreh ich das gerne mal. Da das nicht der erste Fehler ist den ich in dem Buch entdeckt habe, bei den anderen konnt ich mir selber noch weiterhelfen, wird das wohl zu eBay wandern. Bleibt nur noch die Frage was ich mir als alternativ Literatur besorge.PS: Danke für den Link.
-
Zum Ersten: Wer kommt denn auf die clevere Idee, eine static-Variable als temporären Wert für den Post-Inkrement zu verwenden? tmp wird beim allerersten Aufruf des Operators gefüllt und bleibt danach konstant.
Korrekterweise solltest du das static weglassen (und die Rückgabe per Referenz auch).Zweitens: Das & an der Stelle ist kein Adress-Operator, sondern sagt aus, daß die Methode eine Referenz zurückgibt - dadurch ermöglichst du es, das zurückgegebene Objekt direkt weiterzuverarbeiten.
PS: Zu J.W. sage ich jetzt nichts - aber du hast da gerade einen Grund dafür ausgegraben, warum er hier so unbeliebt ist
-
-
Ist das Listing jetzt aus'm Buch abgetippt? Falls ja:
So eine gequirlte Kacke in einem Buch zu sehen tut echt weh. Schmeiß es bloß weg und vergiss alles, was Du darin gelesen hast.
-
klingt.net schrieb:
// complex5.cpp #include <iostream> using namespace std; class myComplex { private: double _real; double _image; public: myComplex( double val1=0.0, double val2=0.0 ) { _real = val1; _image = val2; } void print_Complex( ) { cout << _real << "+" << _image << "\n"; } // Präfix-Operator ++ überladen myComplex& operator++() { _real++; _image++; return *this; } // Postfix-Operator ++ überladen myComplex& operator++(int) { static myComplex tmp(*this); _real++; _image++; return tmp; } }; int main( void ) { myComplex val1(1.1, 2.2); ++val1; cout << "Wert von val1: "; val1.print_Complex( ); val1++; cout << "Wert von val1: "; val1++.print_Complex( ); cout << "Wert von val1: "; val1.print_Complex( ); return 0; }
lol
Das ist soo schlecht, das kann nicht nur aus Unwissenheit entstammen. Jürgen Wolf muß ein Troll sein.
-
CStoll schrieb:
Zum Ersten: Wer kommt denn auf die clevere Idee, eine static-Variable als temporären Wert für den Post-Inkrement zu verwenden?
Wahrscheinlich hat ihm jemand gesagt, dass er keine Referenzen auf temporäre Objekte zurückgeben darf. Da hat er die Lebensdauer etwas verlängert
Mal abgesehen von den ganzen codetechnischen Mängeln: Was soll Inkrementieren bei ner komplexen Zahl überhaupt sein? Ich hätte höchstens erwartet, dass der Realteil inkrementiert wird. So siehts eher aus nach Exkrementieren.
-
klingt.net schrieb:
Da das nicht der erste Fehler ist den ich in dem Buch entdeckt habe, bei den anderen konnt ich mir selber noch weiterhelfen, wird das wohl zu eBay wandern.
Bitte nicht. Am Ende kauft das noch jemand.
-
Michael E. schrieb:
CStoll schrieb:
Zum Ersten: Wer kommt denn auf die clevere Idee, eine static-Variable als temporären Wert für den Post-Inkrement zu verwenden?
Wahrscheinlich hat ihm jemand gesagt, dass er keine Referenzen auf temporäre Objekte zurückgeben darf. Da hat er die Lebensdauer etwas verlängert
Dann sollte man ihm als nächstes beibringen, daß es bei manchen Funktionen nicht sinnvoll ist, Referenzen zurückzugeben
@volkard: Ist es dir auch schon aufgefallen? JW ist schon lange genug hier verrufen
-
CStoll schrieb:
@volkard: Ist es dir auch schon aufgefallen? JW ist schon lange genug hier verrufen
Bisher galt er aber nur als unfähig, nun sind wir schon auf der Stufe wo man annehmen muss, dass er das mit Absicht macht.
-
CStoll schrieb:
Dann sollte man ihm als nächstes beibringen, daß es bei manchen Funktionen nicht sinnvoll ist, Referenzen zurückzugeben
Wartet, bis C++ einen Garbage-Collector hat. *grusel*
-
Die Art es auszugeben gefällt mir
.
-
Dann merke ich noch an, daß der op++(int) den Nutzcode des op++() dupliziert, statt ihn aufzurufen.
-
volkard schrieb:
Dann merke ich noch an, daß der op++(int) den Nutzcode des op++() dupliziert, statt ihn aufzurufen.
Ich glaube alle Schwächen im Code auf zu zählen, wird ein lange Liste
. Ich mache mal weiter: Initialisierungsliste.
-
EOutOfResources schrieb:
Die Art es auszugeben gefällt mir
.
War klar, dass du daran rummeckerst. Es weiß doch jedes Kind, dass man
operator<<(ostream&, MyType)
auf jeden Fall schon erklären muss, bevor die erste eigene Ausgabe gemacht werden soll, insbesondere voroperator+
.
-
SeppJ schrieb:
volkard schrieb:
Dann merke ich noch an, daß der op++(int) den Nutzcode des op++() dupliziert, statt ihn aufzurufen.
Ich glaube alle Schwächen im Code auf zu zählen, wird ein lange Liste
. Ich mache mal weiter: Initialisierungsliste.
int main(void)
-
Michael E. schrieb:
[...]
Er soll's lassen wenn er's nicht richtig macht...
-
Michael E. schrieb:
EOutOfResources schrieb:
Die Art es auszugeben gefällt mir
.
War klar, dass du daran rummeckerst. Es weiß doch jedes Kind, dass man
operator<<(ostream&, MyType)
auf jeden Fall schon erklären muss, bevor die erste eigene Ausgabe gemacht werden soll, insbesondere voroperator+
.Für dieses Beispiel erst den op<< bauen. Dann erst den op++ bauen. Das sagt doch nicht, daß man den op<< bauen sollte, bevor man einen op<< benutzt.
Aber das Beispiel ist eh nicht gut gewählt.
Eine gute Reihenfolge der Lehrinhalte zurechtzuschuggern ist schon mühsam. Aber da muß ein Autor durch.
-
EOutOfResources schrieb:
Michael E. schrieb:
[...]
Er soll's lassen wenn er's nicht richtig macht...
Tut mir Leid, aber das ist Blödsinn. Sobald Klassen eingeführt wurden, will ich Member ausgeben. Soll dann direkt operator<< überladen werden? Am besten noch bevor der Leser weiß, was
public
undprivate
heißen.