Wieso operator + mit += implementieren??
-
otze schrieb:
die erste version kriegste nur innerhalb der klasse hin der + operator gehört aber nach draussen.
UNSINN! Funktionier einwandfrei!
class Rational { public: float n_; float d_; Rational (void); Rational (const Rational &rational); Rational (float n, float d); ~Rational (void){}; }; inline const Rational operator+ (const Rational& left, const Rational& right) { return Rational (left.n_+right.n_,left.d_+right.d_); } int main (void) { Rational r1 (4, 2); Rational r2 (33, 3); cout << (v1+v2).d_ << endl; }
-
schonmal was vom OCP gehört?
danke für ihre aufmerksamkeit
-
BTW: Ich hoffe, dir ist klar, dass dein Operator folgendes nicht macht: "2 rationale Zahlen addieren".
-
und warum laberst du dann so einen stuss von "die läuft nur in der klasse" Wärste gleich mit deinem Ach so geilen OCP gekommen hätt ichs ja noch verstehen können, aber nein wir kommen mit einer Behauptung die fürn hintern ist.
-
Gregor schrieb:
BTW: Ich hoffe, dir ist klar, dass dein Operator folgendes nicht macht: "2 rationale Zahlen addieren".
ja weil ich keinen gemeinsamen nenner suche, ist doch schnuppe, dient nur zur veranschaulichung.
-
ich setz voraus, dass man die grundregeln des programmierens in einer sprache kennt, woher soll ich wissen, dass du keine ahnung vom ocp hast und gleich rumtrollen musst
-
------- schrieb:
ja weil ich keinen gemeinsamen nenner suche, ist doch schnuppe, dient nur zur veranschaulichung.
Ja, war auch nur so ne Nebenbemerkung. ...man weiß ja nie!
-
otze schrieb:
ich setz voraus, dass man die grundregeln des programmierens in einer sprache kennt, woher soll ich wissen, dass du keine ahnung vom ocp hast und gleich rumtrollen musst
Seit wann ist das OCP eine Richtlinie an der sich jeder zu halten hat? Es ist ein Privileg. Und seit wann ist dies eine "grundregel" des Programmierens? Ich definiere mit einer Grundregel sowas nicht zu machen:
while(new char);
-
@otze
Was bedeutet OCP? Ich kenne nur das Open-Closed-Principle, dass steht aber in keinem Zusammenhang mit einem Operator+ der als freie Funktion definiert wurde und einen "computational constructor" benutzt.
Kannst du deine Gedanken mal offen legen?Der Grund dafür, dass man den op+ über den op+= implementieren sollte ist Symmetrie. Du erhälst dadurch zwei große Vorteile:
1. Ist der op+= korrekt implementiert, erhälst du automatisch eine korrekte Implementation des op+.
2. Verringerte Komplexität: Da die Funktionalität nur in einer Funktion implementiert ist (siehe DRY - Don't repeat yourself), sinkt die Komplexität in Bezug auf Wart- und Testbarkeit.Zur Performance:
In Variante 1 hast du zwei Additionen sowie zwei Ctor-Aufrufe wovon einer dank RVO wegfallen kann.In Variante 2 hast du zwei Ctor-Aufrufe, einen Aufruf des op+= und zwei Additionen. Der zweite Ctor-Aufruf kann aber dank NRVO wegfallen.
Sllte der op+= jetzt noch inline-generiert werden, hast du nicht mehr Aufrufe als in Variante 1.Variante 2 ist potentiell langsamer (NRVO ist seltener als RVO) als Variante 1, hat dafür aber Vorteile in den Disziplinen: Wartbarkeit, Korrektheit, Komplexität.
Abhängig von den Optmierungsfähigkeiten des Compilers kann Variante 2 aber genauso effizient sein wie Variante 1, unter Beibehaltung der genannten Vorteile.Du solltest also Variante 2 nehmen. Optimieren kannst du später immer noch (hier nur, wenn dir ein Profiler wirklich bestätigt hat, dass der Op+ deinen Code bremst).
-
@Hume
das open closed principle wird dort gebrochen, wo die elemente die private sein sollten public sind.
denn fakt ist, das man in einer bruch klasse(das sollte es doch sein oder?) nenner und zähler nicht public machen sollte, bei bruchklassen würd ich sogar auf geter/seter verzichten,weil sie nichts bringen würden, ein bruch wird als x/y definiert, und ab dann zählt nurnoch der Wert, den der bruch darstellt.
Mathematisch gesehen sind operatoren die einzige möglichkeit einen bruch zu verändern, und so sollte man es auch implementieren.
und somit verstößt die klasse und der operator+ der die public vars ausnutzt gegen das ocp.sollte die Klasse etwas andres darstellen, so bleibt mir der sinn verborgen^^
-
otze schrieb:
@Hume
das open closed principle wird dort gebrochen, wo die elemente die private sein sollten public sind.
denn fakt ist, das man in einer bruch klasse(das sollte es doch sein oder?) nenner und zähler nicht public machen sollte, bei bruchklassen würd ich sogar auf geter/seter verzichten,weil sie nichts bringen würden, ein bruch wird als x/y definiert, und ab dann zählt nurnoch der Wert, den der bruch darstellt.
Mathematisch gesehen sind operatoren die einzige möglichkeit einen bruch zu verändern, und so sollte man es auch implementieren.
und somit verstößt die klasse und der operator+ der die public vars ausnutzt gegen das ocp.Sorry in meinen Augen redest du wirr.
Erst sagst du, dass man die erste Version des op+ nur als Memberfunktion implementieren kann -> käse.
Dann kommst du auf einmal mit dem OCP. Deine Begründung hat dann aber überhaupt gar nichts mit dem op+ zu tun sondern einzig und allein mit public-Variablen, die wiederum aber wieder überhaupt nichts mit dem op+ zu tun haben:class Rational { public: Rational (float n, float d); friend const Rational operator+(const Rational& lhs, const Rational& rhs); private: float n_; float d_; }; const Rational operator+(const Rational& lhs, const Rational& rhs) { return Rational (lhs.n_+rhs.n_,lhs.d_+rhs.d_); }
Fertig. Wo wurde jetzt das OCP verletzt?
Hättest du erst die Frage beantwortet und dann noch einen Hinweis auf die Unangebrachtheit von public-Variablen gebracht, ok. Aber so sieht das für mich
einfach nur nach Buzzword-Bingo aus.Wenn's das nicht ist, dann erklär mir deine Gedanken mal bitte ganz langsam. So das auch ich sie nachvollziehen kann.
-
HumeSikkins schrieb:
Buzzword-Bingo
-
zuerst sagte ich wie du richtig herausgestellt hast, dass der op+ so wie er da stand nicht ausserhalb einer klasse definiert werden kann-es fehlte halt das berühmte buzzword "friend",welches aber in der nachfolgenden beispielimplementierung nicht nachgeliefert wurde, währe da ein friend gekommen hätt ich gesagt: "ok alles in ordnung sorry für den kommentar", aber nein, stattdessen wurden mir wunderbare public variablen angeboten, die-und das kannst du nicht abstreiten- in diesem fall eindeutig das OCP verletzt haben, womit die implementierung des op+ sofort schlechter wird als die ocp unterstützende benutzung des op += innerhalb des op+,und darum gings ja auch in dem thread, was besser ist, oder? Du beschäftigst dich mit der funktionalität, ich mich mit der Kapselung (weshalb ich auch normalerweise friend operatoren vermeide btw)
Und wehe, jetzt geht hier ein flamewar los, was kapselung mit dem OCP zu tun hat^^
-
@Threadersteller: Warum postet du nicht mit deinem richtigen Nick "nix da"? Sind dir die Fragen zu peinlich?
-
otze schrieb:
zuerst sagte ich wie du richtig herausgestellt hast, dass der op+ so wie er da stand nicht ausserhalb einer klasse definiert werden kann-es fehlte halt das berühmte buzzword "friend",welches aber in der nachfolgenden beispielimplementierung nicht nachgeliefert wurde, währe da ein friend gekommen hätt ich gesagt: "ok alles in ordnung sorry für den kommentar", aber nein, stattdessen wurden mir wunderbare public variablen angeboten, die-und das kannst du nicht abstreiten- in diesem fall eindeutig das OCP verletzt haben, womit die implementierung des op+ sofort schlechter wird als die ocp unterstützende benutzung des op += innerhalb des op+,und darum gings ja auch in dem thread, was besser ist, oder? Du beschäftigst dich mit der funktionalität, ich mich mit der Kapselung (weshalb ich auch normalerweise friend operatoren vermeide btw)
Und wehe, jetzt geht hier ein flamewar los, was kapselung mit dem OCP zu tun hat^^
Was hat Kapselung mit dem OCP zu tun?
-
Hier herrscht ein Tonfall.... wie im Kindergarten
-
MDas ist ne faustregel, mehr nicht. Gibt genügend Fälle wo das nicht so ist - aber: Wenn man operator+ "direkt" implementiert, sollte man triftige Gründe haben.
-
Gründe für die Faustregel
a.operator+=(b) sollte das gleiche Ergebnis haben wie a=a+b Die Arithmertik dafür sollte an einer Stelle liegn /Reduktion der Fehlerquellen, Stellen für Modifikationen)
Nun hat man die Wahl, operator+ mit Hilfe von += zu implementieren - oder andersherum. Variante 1 ist simpel, Variante 2 dämlich: erstens hat += von Natur aus Zugriff auf Klasseninterna, operator+ als nur assoziierte Funktion aber nicht. Zweitens braucht operator+ im Normalfall sowieso eine temp-Variable, die die mögliche bessere performance von += verdirbt. Außerdem ist der + - Operator komplexter (drei statt zwei entities), also die Gefahr eines Fehlers deutlich höher.
Wie schlimm ist also die zweite temporäre variable?
Wenn der Konstruktor "teuer" ist, sollte operator+ an Performance-kritischen Stellen sowieso vermieden werden. Ist der Konstruktor primitiv, kann der Optimizer den größten Teil des overheads rausschmeißen.In deinem Beispiel: operator+ über += imkplementiert benötigt 12 ASM-Befehle, die "Handimplementation" 9 von ähnlicher Komplexität. Die erhöhten Entwicklungskosten lohnen sich also nur, wenn die Klasse hochkritisch ist und die Kosten des Copy- bzw. Memberassign-Konstruktors in der gleichen Größenordnung wie += liegen.
-
-
otze schrieb:
Du beschäftigst dich mit der funktionalität, ich mich mit der Kapselung (weshalb ich auch normalerweise friend operatoren vermeide btw)
Wenn du Kapselung nicht nur so als Begriff verwenden würdest, sondern dich mit dem Konzept dahinter beschäftigen würdest, würdest du feststellen, dass friend keinerlei negative Einwirkungen auf die Kapselung hat (nicht mehr als eine Methode auch). Besonders wenn es sich nicht um ein "long distance friendship" handelt.
Und wehe, jetzt geht hier ein flamewar los, was kapselung mit dem OCP
zu tun hat^^Es ging hier nicht um einen flamewar sondern um eine Diskussion. Aber mit dir zu diskutieren scheint eh sinnlos, da du nicht mal versuchst etwas sinnvolles beizutragen.
-
friend und encapsulation:
http://www.parashift.com/c++-faq-lite/friends.html
"Do friends violate encapsulation? No! If they're used properly, they enhance encapsulation."siehe auch: http://www.gotw.ca/gotw/070.htm
"Get your interfaces right first. Internals are easy enough to fix later, but if you get the interface wrong you may never be allowed to fix it."http://www.gotw.ca/gotw/004.htm (class Complex)
"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"."
op+= als Member-Funktion, op+ wird außerhalb der Klasse realisiert und verwendet intern op+=:const Complex operator+( const Complex& lhs, const Complex& rhs ) { Complex ret( lhs ); ret += rhs; return ret; }
Bei boost::rational wird op+= ebenfalls als Member-Funktion realisiert, op+ ist im header rational.hpp überhaupt nicht aufgeführt, soweit ich das erkennen kann. Muss irgendwie anders realisiert sein, konnte leider nicht genau erkennen wie. Vielleicht weiß das jemand genau?
zu op+ und op+= siehe auch: http://coding.derkeiler.com/Archive/C_CPP/comp.lang.cpp/2003-10/2715.html
otze hat übrigens dort Recht, wo er behauptet, dass Zähler und Nenner private sein sollten. Das war, soweit ich das erkennen konnte, sein Hauptziel. Er hat auch ausgeführt, dass op+ außerhalb der Klasse realisiert werden soll.
Allgemein zum Optimieren:
http://www-2.cs.cmu.edu/~gilpin/c++/performance.html#temporaries
dort findet sich ebenfalls:
"Temporaries can be avoided by using <op>= operators. For example, the code
a = b + c;
could be written as
a=b;
a+=c;."PS: Der nichtregistrierte Fragesteller hat hier einen Ton angeschlagen, der in keinster Weise zur Komplexität der Frage passt. Daher sollte man zumindest auch im Forum C++ nur registrierte Nutzer zulassen, damit dieser Mischung aus primitivem Getrolle (das jeder gut versteht und entsprechend emotional reagiert) und Fachchinesisch (das nicht jeder versteht, z.B. OCP, RVO, NRVO, ..., und daher Missverständnisse und Unklarheiten die Folge sind) ein baldiges Ende beschert sein möge. Dann sollte es wieder möglich sein, fachliche Fragen vorwiegend fachlich zu diskutieren. Humor ist allerdings erlaubt.
-
Da ja nun geklärt ist, das man den op+ über op+= implementiert
hab ich mal 'ne Frage an die Profis. Zur Auswahl stehen zwei op+ Implementierungen:
foo operator +(const foo& lhs, const foo& rhs) { return foo(lhs) += rhs; }
foo operator +(foo lhs, const foo& rhs) { return lhs += rhs; }
Variante 1 kann mein Compiler teilweise besser optimieren. Allerdings kann es uU Compilerfehler geben, wenn die Klasse aligned ist. Wohin schlägt also das Pendel: 1, 2 oder sollte man von Fall zu Falls unterscheiden?
// edit
Hoppla, da ist mir doch beim Kopieren ein dummer Fehler unterlaufen.
-
groovemaster2002 schrieb:
Variante 1 kann mein Compiler teilweise besser optimieren. Allerdings kann es uU Compilerfehler geben, wenn die Klasse aligned ist.
Kannst Du das genauer erklären?
Ich verwende grundsätzlich Variante 1, weil sie ohne irgendwelche Tricks und Schnörkel einfach funktioniert. (+ ist normalerweise symmetrisch, also sollten auch die Parameter auf die selbe Art übergeben werden. Von einem Problem mit dieser Variante habe ich noch nie was gehört.
MfG Jester