operator ++ - *this rückgabe
-
Mh "*this" ist "math&"? Aber "math&" heißt doch das man eine Referenz zurückgibt oder?
-
Wo ist das Problem? this ist ein Zeiger auf das Objekt, und *this das Objekt selbst. Du solltest aber beim operator++ eine Referenz zurückgeben:
int a = ...; int b = ++a; // wenn hier ein zeiger zurückkommen würde, dann würde das nicht gehen
-
Mh, also kp, ich checks einfach net. Dann könnt mans doch au so machen:
#include <iostream> using namespace std; class math { public: math(); ~math(); const math operator++ (); const math operator++ (int); private: int A; }; const math math::operator++ () { ++A; return *this; } const math math::operator++ (int) { A++; return *this; } int main() { return 0; }Und eine Referenz ist doch sowie ein Imitator, die Referenz macht genau das selbe was ihr\e Objekt\Variable macht mit dem sie verbunden ist.
Also sowas ist doch eine Referenz:int a=1; int &REF(a);MfG
Stromberg
-
-
Objekt per referenz zurückgeben (&):
const math& math::operator++ (int) { A++; return *this; }
-
Sollte ich noch darauf hinweisen, daß dein Post-Inkrement die falsche Semantik hat? Normalerweise gibt Prä-Inkrement das Objekt nach der Erhöhung (meist als Referenz) und Post-Inkrement das Objekt VOR der Erhöhung (idR als Kopie) zurück:
class math{ public: math& operator++() { ++A; return *this; } math operator++(int) { math tmp=*this; ++(*this); return tmp; } };
-
Warum macht man das so?:
class math{ public: math& operator++() { ++A; return *this; } math operator++(int) { math tmp=*this; ++(*this); return tmp; } };Wird der Code dann schneller?
Und, ich versteh das mit der Referenz immer noch nicht. Irgendwie weiß auch nicht, ich weiß schon was eine Referenz ist, aber da sieht des so komisch aus.
Und warum gibt man den da auch eine Referenz zurück, bzw wo ist den jetzt der Unterschied zwischen:
1.#include <iostream> using namespace std; class math { public: math(); ~math(); const math operator++ (); const math operator++ (int); private: int A; }; const math math::operator++ () { ++A; return *this; } const math math::operator++ (int) { A++; return *this; } int main() { return 0; }2.
using namespace std; class math { public: math(); ~math(); const math * operator++ (); const math * operator++ (int); private: int A; }; const math & math::operator++ () { ++A; return *this; } const math & math::operator++ (int) { A++; return *this; } int main() { return 0; }Man will doch einfach das soeben inkrementierte\dekrementiert Okjekt zurückgeben. Für was die Referenz, und wie soll ich mir das dann vorstellen, "math" ist der Type, und was ist in diesem Zusammenhang dann "*this". Ich weiß nicht ob mich jemand versteht, aber für mich ist das allgemein wie das hingeschrieben ist verwirrend, ich kann mir da nichts drunter vorstellen.
Weil eine Referenz ist für mich sowas, das nach diesem Schema aufgebaut ist:
[cpp]
int a;
a=20;
int &REF=a; //"REF" hat nun den Wert 20 und verändert sich wenn "a" sich verändert, und "a" veränder sich wenn "REF" sich verändert.
Kann jemand nochmal erklären?MfG Stromberg
-
den unterschied zwischen inkrement und dekrement ist dir klar oder?
-
Stromberg schrieb:
Warum macht man das so?:
class math{ public: math& operator++() { ++A; return *this; } math operator++(int) { math tmp=*this; ++(*this); return tmp; } };Wird der Code dann schneller?
Der Code wird dann semantisch richtig (Stichwort: "do it as the int's") und konsistent (du mußt nur einen Operator ändern und der zweite passt sein Verhalten automatisch an).
Und, ich versteh das mit der Referenz immer noch nicht. Irgendwie weiß auch nicht, ich weiß schon was eine Referenz ist, aber da sieht des so komisch aus.
Eine Referenz gibt man häufig dann zurück, wenn es zu teuer ist, die Objekte zu kopieren.
Und warum gibt man den da auch eine Referenz zurück, bzw wo ist den jetzt der Unterschied zwischen:
1.#include <iostream> using namespace std; class math { public: math(); ~math(); const math operator++ (); const math operator++ (int); private: int A; }; const math math::operator++ () { ++A; return *this; } const math math::operator++ (int) { A++; return *this; } int main() { return 0; }2.
using namespace std; class math { public: math(); ~math(); const math * operator++ (); const math * operator++ (int); private: int A; }; const math & math::operator++ () { ++A; return *this; } const math & math::operator++ (int) { A++; return *this; } int main() { return 0; }Das zweite ist technisch falsch, weil du Referenzen und Zeiger durcheinanderwirfst.
Man will doch einfach das soeben inkrementierte\dekrementiert Okjekt zurückgeben. Für was die Referenz, und wie soll ich mir das dann vorstellen, "math" ist der Type, und was ist in diesem Zusammenhang dann "*this". Ich weiß nicht ob mich jemand versteht, aber für mich ist das allgemein wie das hingeschrieben ist verwirrend, ich kann mir da nichts drunter vorstellen.
'this' ist ein Zeiger auf das Objekt, dessen op++ du aufgerufen hast - und '*this' ist das Objekt dahinter - also genau das Objekt, was du inkrementiert hast.
Weil eine Referenz ist für mich sowas, das nach diesem Schema aufgebaut ist:
[cpp]
int a;
a=20;
int &REF=a; //"REF" hat nun den Wert 20 und verändert sich wenn "a" sich verändert, und "a" veränder sich wenn "REF" sich verändert.
Kann jemand nochmal erklären?MfG Stromberg
Ja, das ist auch eine Verwendung vor Referenzen - als Aliasbezeichnung für bereits existierende Namen (die sieht man normalerweise nicht als eigenständige Objekte an - REF ist "nur" ein anderer Name für a). Aber Referenzen sind vielseitiger als das dort - vor allem in Zusammenarbeit mit const werden sie häufig verwendet, um call-by-value Semantik ohne den Aufwand von Objektkopien zu erreichen.
-
Stromberg schrieb:
Warum macht man das so?:
class math{ public: math& operator++() { ++A; return *this; } math operator++(int) { math tmp=*this; ++(*this); return tmp; } };Es ist konsistent, dh es ist schöner, besser, sicherer

Letzendlich willst du mit ++ egal ob pre oder post den Wert erhöhen, dabei bietet es sich natürlich an es nur einmal zu implementieren und das in Pre++. Post++ benutzt dann Pre++ und bei Anderungen müsstest du nur Pre++ ändern.Zu der Referenz Geschichte. this ist ja dein Zeiger auf dein akt. Objekt. *this ist dann dein Objekt. Wenn du nun *this zurück gibst als math wird *this kopiert. Das kostet natürlich Zeit, also gibst du ne Referenz darauf zurück, da das Objekt ja noch gültig ist, hingegen bei post++ nicht, da tmp eine lokale Variable ist und somit kopiert werden muss. Zudem sollte deine Operatoren das tun, was man zB von anderen Typen auch erwartet:
int a = 4; ++a = 3; // a = 3 //dein math Pre++ ohne Referenz math a = 4; ++a = 3; // a = 4, da du nur eine Kopie geändert hast und nicht die Referenz auf *this //--------------- int a = 4; a++ = 2; // :warning: a++ ist kein lvalue, da es ja nicht a sondern nen temp = 4 zurück gibt. //Post++ mit const math math a = 4; a++ = 2; // gut klappt auch nicht, da nen const Objekt zurückgegeben wird
-
man benutzt referenzen, damit man sich den aufruf eines copy-ctors spart.
wenn du ein "normales" objekt zurückgibst, bspw so:math math::operator++ () { ++A; return *this; }wird in der zeile "return *this" implizit mittels eines copy-ctors ein neues objekt erstellt.
desweiteren übergibt man referenzen (übrigens normalerweise keine konstanten), damit sich deine operatoren so verhalten, wie die standard-operatoren auch. mit einem operator++() sollte so etwas möglich sein:
math a; ++++a;hier sollte a am ende um 2 inkrementiert sein, was aber nur klappt wenn man eine nicht const-referenz zurückgibt. im falle des normalen objektes wird eine kopie bereits im operator selber erzeugt und a nur um 1 erhöht. bei einer kostanten referenzen sollte der compiler meckern.
nicht übermäßig elegant, aber ich hoffe du verstehst, was ich meine.
-
@Stromberg: Achja, noch zu Referenzen: http://c-plusplus.net/forum/viewtopic-var-p-is-1330752.html#1330752
-
Okay, das mit den Referenzen und so hab ich gecheckt. Weil sonst eine vollständige kopie gemacht wird....und das zeit kostet...
Aber wie ich mir das jetzt noch genau vorstellen kan weiß ich no net so genau, also z.B. bei dem Beispiel hier:math& math::operator++() { ++A; return *this; }Kann ich mir das so vorstellen, das nach dem Rückgabetyp "math&" da einfach noch eine unsichtbare Variable namens "REF" steht, und diese dann die Referenz von dem wird, das am schluss mit "return" zurückgegeben wird? Also so: (das was ich jetzt in "[]" schreibe stell ich mir bloß vor, entsteht also nur in meinem kleinen kranken Hirn, und ich würds natürlich nicht hinschreiben...nicht das sich jemand von euch aufregt.)
math& [REF] math::operator++() { ++AA; return REF; // und REF ist halt einfach [REF=*this] }Darf ich mir das so vorstellen, weil da steht irgendwie nie eine Name und so, und kp ich hab da dann kein bezug und chekcs net. Und das ist für mich jetzt ganz einfach und logisch verständlich, fast wie:
int a=10; int &REF=a;Weil so stell ich mir Referenzen eigentlich vor.
Ist meine Vorstellung jetzt korrekt, wie denkt ihr euch das im Kopf?
MfG
Stromberg
-
Stromberg schrieb:
Ist meine Vorstellung jetzt korrekt, wie denkt ihr euch das im Kopf?
Hab nicht ganz verstanden, was du meinst

Für mich sind jedenfalls Referenzen das selbe wie Pointer - nur eben mit einer anderen Schreibweise. Und Pointer selber beinhalten ja nur die Adresse von einer Variablen, dabei können natürlich auch mehrere Pointer dieselbe Adresse beinhalten. Aber ich will hier nicht Pointer erklären, für den Fall dass du dich da noch nicht so auskennst, kann dir vielleicht Binky weiterhelfen

-
ich hab das gefühlt, dich haben die referenzen jetzt endgültig verwirrt.

wenn man eine referenz zurückgibt, heißt dieses vor allem, dass man bei return kein neues objekt erstellt, sondern das objekt selber zurückliefert. in deinem schreib stil sähe das etwa so aus:
//für ein objekt nennen wir es a und den operator++ math a; //so sieht dann die eigentlich funktion aus: &[a] operator++() { ++A; return [a]; }es wird eben keine neue referenz oder variable erzeugt, sondern das objekt selber wird weiter genutzt.
allerdings ist es so, dass du bei zuweisung dann doch ein neues objekt erstellst.(um mal deinen code weiter zu nutzen):math a; math b; b=++a; //<- hier wird b nicht mit &a belegt, sondern mit einer kopie von a.das hat etwas damit zu tun, dass operator=() und der copy-ctor grundsätzlich mit einer const & als parameter versorgt werden.
die vorstellung mit der REF geht daher ein bisschen am sinn des ganzen vorbei.
-
Also jetzt blick ich irgendwie gar nimma so durch, vorhin hat hier irgendjemand folgenden link gepostet --> http://www.c-plusplus.net/forum/viewtopic-var-t-is-39454.html
Hab ich mir jetzt halt mal angeschaut, und dann kam der Code hier vor:#include <iostream> class foo { public: foo(int nr):m_nr(nr) {} foo & operator++ () // Präfix { ++m_nr; return *this; } const foo operator++ (int) // die Postfix-Version bekommt ein int-dummy Parameter { // um sie von der Präfix-Version unterscheiden zu können foo tmp(*this); ++(*this); // benuzt den Präfix-Operator return tmp; } private: int m_nr; }; int main() { return 0; }Das verstehe ich nicht, warum wird beim Postfix Operator keine Referenz zurückgegeben. Wenn ich bis jetzt alles richtig gecheckt habe, dann heißt es doch "freies Objekt ohne Referenz --> KOPIE --> Zeitaufwand", "Referenz --> keine KOPIE --> nicht so großer Zeitaufwand"....so mhm??? Also würde ich das so machen:
#include <iostream> class foo { public: foo(int nr):m_nr(nr) {} foo & operator++ () // Präfix { ++m_nr; return *this; } const foo & operator++ (int) // die Postfix-Version bekommt ein int-dummy Parameter { // um sie von der Präfix-Version unterscheiden zu können foo &tmp(*this); ++(*this); // benuzt den Präfix-Operator return tmp; } private: int m_nr; }; int main() { return 0; }Und was ich noch nicht verstehe warum wird da extra ein "foo tmp" Objekt angelegt, es würde doch reichen wenn man einfach "++(*this)" macht und dieses dann return (der Rückgabetyp muss dann halt eine Referenz sein..schon klar).
Kann mir nochmal jemand helfen?
MfG
Stromberg
-
Du scheinst an der Stelle ein Verständnisproblem mit dem Postfix-Inkrement zu haben. Dieser liefert das Objekt vor der Inkrementierung zurück. Da zu dem Zeitpunkt der Rückgabe aber das Objekt bereits inkrementiert wurde, muss das Objekt vor der Inkrementierung logischerweise eine Kopie sein. Ein Objekt kann nicht gleichzeitig den neuen und alten Wert besitzen

Und da "tmp" eine lokale Variable innerhalb der Funktion ist, die am Ende der Funktion zerstört wird, kannst Du keine Referenz auf sie zurückgeben. D.h. Du kannst schon, aber das wird nicht das erwartete Ergebnis bringen.
-
Das hat eine ganz einfache Ursache:
Wenn mana=x++schreibt, will man an der Stelle des "x++", dass das x erhöht wird, aber man will noch mit dem ursprünglichen Wert weiterarbeiten. Deshalb wird normalerweise bei "x++" intern das x erhöht und ein neues Objekt zurückgegeben, das dem x vor dem Erhöhen entspricht.Hier
const foo & operator++ (int) { foo &tmp(*this); ++(*this); return tmp; }ist "tmp" eine Referenz, die das aktuelle Objekt referenziert. Das Objekt wird um eins erhöht und die Referenz zurückgegeben. Das Problem dabei ist, dass dann schon das "erhöhte" Objekt zurückgegeben wird (es wird ja das aktuelle zurückgegeben und "tmp" verweist ja auf "*this").
Also legt man normalerweise eine Kopie an:foo tmp( *this );, was ein vollwertiges neues Objekt mit dem Zustand von x ist. Dann erhöht man das richtige x++(*this)und gibt das Objekt mit dem nicht-erhöhten Zustand zurückreturn tmp;. Eine Referenz darauf zurückgeben, würde nicht funktionieren, da das neu erzeugte Objekt beim Verlassen der Funktion zerstört wird - die Referenz würde ins Nirvana zeigen.
-
Ah okay, is klar, des hab ich wirklich ma verstanden.
-
MH ne doch nicht ganz, warum verwndet man nur beim postfix operator ein "const"?
MfG
Stromberg