operator +\- überladen - Warnugen
-
Stromberg schrieb:
math math::operator- (const math &rhs) const { return math(A-rhs.Get_A()); //man sollte es aber explizit machen. ;) }Das nennt sich Return-Value-Optimization, der Compiler hat die Wahlfreiheit das temporäre Objekt wegzuoptimieren. Wenn Du das getrennt schreibst, gibt es die Möglichkeit nicht mehr.
Grüße
-
~john schrieb:
Das nennt sich Return-Value-Optimization, der Compiler hat die Wahlfreiheit das temporäre Objekt wegzuoptimieren. Wenn Du das getrennt schreibst, gibt es die Möglichkeit nicht mehr.
Grundsätzlich richtig, aber spätestens sein NRVO kann ein besserer Compiler auch die getrennte Variante optimieren.
-
Stromberg schrieb:
Sag mir doch bitte was ich daran verbesser könnte. Das ist doch nur positiv für mich!!! Wenn ich auf so Kleinigkeiten (oder sinds Großigkeiten?) (ich glaub des Wort gibts net :D) in Zukunft mehr drauf achte, dann wird sich mein Stil, mein Code und hoffentlich auch die Compiler Fehler verbessern.
du könntest konsequent in der bezeichnung sein.

in der stl werden klassen wie auch variablen grundsätzlich klein geschrieben, wobei die variablen meist ein präfix haben.
es gibt andere libs, die sich an den java-standard halten und klassen groß und variablen klein schreiben. irgendeine form der unterscheidung sollte man aber verweden, wobei variabeln groß und klassen klein extrem seltsam aussieht.Stromberg schrieb:
Zu dem Get_A(), das du inline gesetzte hast, also ich hab immer gedacht, Funktionen die man innerhlab der Klasse reinschreibt sind automatisch inline.
sie sind nicht automatisch inline, aber die meisten compiler interpretieren es so.
Stromberg schrieb:
Das hier versteh ich aber leider gar nicht:
return A+rhs.Get_A(); //es reicht den konstruktor implizit aufzurufenDa wird jetzt doch nur eine Zahl zurückgegeben, oder?
in c++ gibt es eine implizite umwandlung zwischen objekten, wenn die klasse einen passenden ctor bereit stellt.
will heißen, wenn du dein ctor der form "klasse(int)" hast, dann kannst du an jeder stelle im code ein int anstelle deiner klasse verwenden. der compiler wird das dann durch den aufruf des ctors ersetzen.
allerdings sollte man die finger von derartigen konstrukten lassen und möglichst immer den ctor explizit aufrufen.Stromberg schrieb:
Aber ich mein Schätzungsweiße, wenn mein Objekt jetzt noch 2 weiter Elementvariblen hätte, also int B,C;....an wenn sollte der Compiler dann die Zahl schicken?
wenn du mehr als einen parameter hast oder genauer mehr als einen parameter ohne defaultwert, dann ist diese variante nicht möglich.
Stromberg schrieb:
Meinst du das es zwischen:
math& math::operator- (const math &rhs) const { math temp(A-rhs.Get_A()); return temp; }und
math math::operator- (const math &rhs) const { return math(A-rhs.Get_A()); //man sollte es aber explizit machen. ;) }Schnelligkeitsunterschied gibt? Oder gehts hier wirklich nur ums aussehen?
es gibt einen geschwindigkeitsunteschied. die erste variante funktioniert nämlich nicht.

man kann keine referenz von lokalen objekten zurückgeben.
wenn die frage dahin ging, ob die variante mit oder ohne lokalen objekte schneller ist, ist die antwort "it depends". es kann im ersten fall sein, dass dein compiler strohdoof ist und tatsächlich erst eine objekt erzeugt und dann bei return mittels copy-ctor ein neues erstellt. bei der anderen variante sollte dieses nie geschehen.Stromberg schrieb:
PS:
Zum "const" noch kurz, wäre es nicht auch gut wenn man bei beiden Operatoren, am Schluss das "math" Objekt noch const macht? Oder ist das egal?const math operator- (const math &rhs) const;man sollte nie konstante objekte zurückgeben, da das nicht sinn und zweck der übung ist. bsp:
math a,b; return ++(a+b);der aufruf ist völlig legal und setzt zwingend voraus, dass der rückgabewert von operator+ eine nicht konstantes objekt ist.
bei dem streaming-operator wird es noch deutlicher:a << b << c;bedeutet eigentlich:
[cpp]
(a << b) << c;
[/cpp}
hier ist es unbedingt notwendig, dass operator<< keine konstante referenz liefert, da sonst der aufruf für << c nicht mehr möglich wäre.
-
Siehts so besser aus:
#include <iostream> using namespace std; class Math { public: Math(int v_a); ~Math(); Math operator+ (const Math &rhs) const; Math operator- (const Math &rhs) const; inline int get_a() const {return a;} private: int a; }; Math::Math(int v_a) :a(v_a) { } Math::~Math() { } Math Math::operator+ (const Math &rhs) const { return Math(a+rhs.get_a()); } Math Math::operator- (const Math &rhs) const { return Math (a-rhs.get_a()); } int main() { Math testing_A(17); Math testing_B(5); Math testing_C(0); testing_C=testing_A-testing_B-testing_B-testing_B; cout << testing_C.get_a() << endl; return 0; }
-
so kann man das lassen.

nein spaß bei seite: es passt so, wenn es zu den coding-richtlinienen deines brötchengebers passt bzw. für dein heimprojekt, wenn du es konsequent durchhältst.
ich persönlich bevorzuge es member-variablen mit m_var zu kenntzeichen. auch bin ich ein fan von d-pointern. aber beides spielt hier keine rolle, wenn du konsequent deinen stil verfolgst.
-
Stromberg schrieb:
"Why write a Complex class when one already exists in the standard library? (And, incidentally, one that doesn't have any of the following problems and has been crafted based on years of practice by the best people in our industry? Humble thyself and reuse!)
Reuse standard library algorithms instead of handcrafting your own. It's faster, easier, AND safer!
Wie soll den diese library heißen? Und wenn ich diese dann verwende, dann sind die ganzen Operatoren wie "+","-","=","++"....schon extra für mich überladen, also für so standard Operationen wie A=C+B. Oder was meint der damit?
Für komplexe Zahlen gibt es die (Template)Klasse std::complex<> (und die Bemerkung bezog sich auf das dort gegebene Beispiel ;))
2.
Prefer using "a op= b" instead of "a = a op b" for arithmetic operations (where appropriate; some classes -- not any that you wrote, right? -- might not preserve the natural relationship between their op and op=).
Also so ungefähr hab ichs verstanden, er sagt doch das in manchane Klassen die Konstelation A=A+B irgendwie nicht funktioniert, und man darum immer A +=B nutzen soll. Hab ich das richtig verstanden? Soll ich jetzt in Zukunft nie mehr A=A+B nutzen sondern immer A +=B? Was genau meint der da jetzt, was soll den bei A=A+B passieren? Kanst du mir das nochmal erklären?
Bei "gut" geschriebenen Klassen liefert "A+=B;" und "A=A+B;" das gleiche Verhalten - aber ersteres ist häufig schneller, weil es keine temporären Hilfsvariablen anlegen muß. Und für Konsistenz wird oft op+ durch op+= ausgedrückt (das könntest du für deine Klasse auch verwenden):
class math { int m_a; public: math(int a) : m_a(a) {} math& operator+=(const math& other) { m_a+=other.m_a; return *this; } ... }; math operator+(const math&l,const math&r) { return math(l)+=r; /* alternativ: math tmp(l); return tmp+=r; */ }3.
operator+ should not be a member function. If it's a member like this, you can write "a=b+1" but not "a=1+b".
Okay, das verstehe ich. Da kann ich dir und dem Autor nur recht geben.

4.
Prefer these guidelines for making an operator a member vs. nonmember function: (Lakos96: 143-144; 591-595; Murray93: 47-49)
- unary operators are members
- = () [] and -> must be members
- += -= /= *= (etc.) are members
- all other binary operators are nonmembersDas Wort "unary" ist gefallen. Zu deutsch glaub "unär", das sind doch Operatoren wie "++", "--" die nicht zwei Seiten haben wie z.B. "+","=" und "-"?
Oder?Ja, unäre Operatoren sind alle, die nur einen Operanden haben - unter anderem Inkrement oder Vorzeichen. (im weitesten Sinne zählen auch Postfix-Inkrement und -Dekrement als unär, aber die werden mitunter gesondert betrachtet)
Was meint er mit dem Punkt hier:
"- = () [] and -> must be members", z.B. "=" kann ich doch auch außerhalb der Klasse überladen, was hindert mich daran, und was ist daran besser wenn es inder Klasse überladen wird? Genauso bei den anderen Operatoren?Nein, die Zuweisung kannst/darfst du nicht global überladen.
"- += -= /= *= (etc.) are members" gibts dafür auch eine Erklärung? Was meint er mit "are members"?
Kurzfassung: Bei denen macht's keinen Sinn, Möglichkeiten wie "7+=b;" anzubieten (und außerdem liegen sie noch nahe an der reinen Zuweisung). Und das "are members" kannst du in dem Zusammenhang lesen als "sollten Methoden sein".
5.
Style: You should normally define op= if you define op. Here, you should define operator+=, since you defined operator+. In this case, the above function should be operator+= in any case (with a tweak for the proper return value, see below).
Ähhh, öööhhh der Satz hier, also ich weiß nicht ob ich das richtig verstehe. Das heißt doch irgendwie, wenn ich den Operator "+" überlade, dann soll ich auch den Operator "+=" überladen oder? Hää? Was genau meint der damit?
Genau das meint er damit - siehe auch die Erklärungen zu Punkt 2.
-
Äh noch kurz was, is mir grad durch Zufall aufgefallen:
ghorst schrieb:
man sollte nie konstante objekte zurückgeben, da das nicht sinn und zweck der übung ist. bsp:
C/C++ Code:
math a,b;
return ++(a+b);
C/C++ Code:
math a,b;
return ++(a+b);der aufruf ist völlig legal und setzt zwingend voraus, dass der rückgabewert von operator+ eine nicht konstantes objekt ist.
bei dem streaming-operator wird es noch deutlicher:C/C++ Code:
a << b << c;
C/C++ Code:
a << b << c;Der Typ von der Englischen Seite hat aber am Schluss folgenden Code:
const Complex operator+( const Complex& lhs, const Complex& rhs ) { Complex ret( lhs ); ret += rhs; return ret; }ist das jetzt richtig oder is es n Fehler?
Dankeschön schon mal im Voraus.
Stromberg
-
Stromberg schrieb:
Der Typ von der Englischen Seite hat aber am Schluss folgenden Code:
const Complex operator+( const Complex& lhs, const Complex& rhs ) { Complex ret( lhs ); ret += rhs; return ret; }ist das jetzt richtig oder is es n Fehler?
Es ist nicht falsch. Anderseits ist bei diesen Dingen nie das letzte Wort gesprochen. Immerhin ist der betreffende Artikel schon verhältnismäßig alt.
Worauf zum Beispiel gründet sich die Empfehlung des Autors, die kombinierten Operatoren (also += -= usw.) als Member zu implementieren? Die Sprache erfordert das nicht - und auch der Vergleich mit primitiven Typen wie int, double spricht eher dagegen. Der Fakt, dass diese Operatoren das Objekt verändern, kann es allein nicht sein - die Streamoperatoren tun das auch (und dort bleibt uns sowieso nichts anderes übrig, als eigene Operatore frei zu implementieren. Erinnern wir uns auch an die Analyse des gleichen Autors hinsichtlich std::string - dort richtet sich die Wahl zwischen freier Funktion und Memberfunktion keineswegs (allein) danach, ob die betreffende Funktion den String verändert. Es geht dort eher um die Unterscheidung zwischen minimalen und "bequemen" Interface. Operatoren, die isoliert implementiert werden, haben nun die unangenehme Eigenschaft, zwei Herren zu dienen. Einerseits erlauben sie die Ausführung einer bestimmten Operation mit dem Objekt (das könnten wir aber auch mit einer normalen Funktion haben). Andererseits präsentieren sie auch noch ein bequemes Interface für den Aufruf. Wohlgemerkt: betrachte diesen Beitrag nicht als Opposition zum verlinkten Artikel, sondern nur als Anstoß um weiterzudenken.
-
Vll. hab ich jetzt mal wieder nen Denkfehler - weil schon so spät ist
- aber warum wird beim Operator "+=" eigentlich noch das "*this" zurückgegeben? Es reicht doch wenn die jeweilige Elemntavriable bearbeitet worden ist....
Kann mir jemand mal n Beispiel sagen, in dem das "*this" wichtig ist?Op & Op::operator+= (const Op &rhs) { m_a += rhs.get_a(); return *this; }Dankeschön schon mal im Voraus.
-
p=allocate_more_memory(current_mem_size+=step_size);kommt selten vor - aber es spricht nichts dagegen soetwas zu verbieten, oder?
-
Stromberg schrieb:
Der Typ von der Englischen Seite hat aber am Schluss folgenden Code:
const Complex operator+( const Complex& lhs, const Complex& rhs ) { Complex ret( lhs ); ret += rhs; return ret; }ist das jetzt richtig oder is es n Fehler?
ein fehler ist es nicht. es ist aber so, dass sich die klasse nicht so verhalten wird, wie es der nutzer erwartet. so funktioniert bspw das hier nicht so wie erwartet:
Complex a,b; return -(a+b);ich bin mir allerdings gerade nicht ganz sicher, was da passiert. entweder es kompiliert gar nicht oder es kann auch sein, dass hier der compiler implizit ein neues Complex-objekt erstellt. aber beides ist nicht das, was der nutzer des codes erwartet.
der erwartet wohl am ehsten, dass da ein objekt als rückgabe wert von + erzeugt wird und dieses dann mit dem unären - operator verändert wird und zu guter letzt zurückgegeben wird (wobei hier wieder eine copy-ctor fällig wird).aber warum wird beim Operator "+=" eigentlich noch das "*this" zurückgegeben? Es reicht doch wenn die jeweilige Elemntavriable bearbeitet worden ist....
es würde in den meisten fällen reichen, allerdings widerspricht es dann dem verhalten der "normalen" operatoren. ein bsp hat shade of mine ja bereits gezeigt. ich denke es wird deutlicher, wenn man das ganze am operator= betrachtet.
if (a=function()) [..]das kommt relativ häufig vor, etwa beim öffnen von datein und ähnlichem. hier wird der rückgabewert des operator= genutzt, um die if-abfrage sicherzustellen. spart also eine zeile code.
-
ghorst schrieb:
der erwartet wohl am ehsten, dass da ein objekt als rückgabe wert von + erzeugt wird und dieses dann mit dem unären - operator verändert wird und zu guter letzt zurückgegeben wird (wobei hier wieder eine copy-ctor fällig wird).
Ich glaube, du bist der Einzige, der erwartet, dass dieser unäre Operator sein Argument verändert. (Diagnose: Kopierphobie
)
-
Okay danke @ all.
Ich würde sagen das sind jetzt alles eher n bissel Komplexe Fälle...und so öfter ich drüber nachdenke, desto mehr veriwrr ich mich dann immer. Aber mir is auch klar warum man jetzt bei "+=" *this zurück gibt... Also so im allgemeinen bin ich mit Operatoren jetzt glaub ganz fit, und so komplizierte Fälle werden ja nicht so oft dran kommen, und wenn dann meld ich mich wieder bei euch ^^
.MfG
Stromberg