Operatoren überladen - nur als Bonus?
-
- Vorsicht vor dem Unterschied zwischen op= und op==!
- Man kann die Operatoren über eine Klassenmethode implementieren, wenn man dadurch irgendwelche Vorteile hat. Ein Beispiel wäre hierfür, wenn man einen Freien Operator implementiert und dazu eine Klassenmethode verwendet, die Zugriff auf private Variablen der Klasse hat. Das geht auch, indem man den op zum friend macht. Was schöner ist, ist Geschmackssache, das Thema hatten wir des öfteren schon.
- http://magazin.c-plusplus.net/artikel/�berladung von Operatoren in CPlusPlus (Teil 1)

-
theliquidwave schrieb:
Ich habe mal eine Frage...
Sollte man überladene Operatoren nur als "Bonus" zur Verfügung stellen, oder diese als festen Bestandteil annehmen?Bonus meiden! Die Schnittstelle soll klein bleiben. Also nicht zwei Funktionen bieten, die genau das selbe machen.
Bei Compare weiß kein Schwein, was rauskommt. Bei < ist alles sonnenklar. Also < nehmen, spart immer wieder einen Guck ins Handbuch.
Aber immer davon abweichen, wenn Du einen guten Grund hast.
-
Eine ähnliche Diskussion (allerdings noch mit
friend) hatten wir kürzlich. Wie du siehst, gibt es verschiedene Meinungen, sobald eineCompare-Funktion nicht genau das Gleiche tut wie ein Operator. In deinem Fall ist aber unbestritten, dassCompare()nichts bringt.
-
Was aber bisher onch nicht angeschnitten wurde, ist die Verwendung deiner Klasse in Funktionen und Klassen der STL. Da kann es sein, dass bestimmte Operatoren Pflicht sind. Ein std::find funktioniert nicht wirklich ohne operator==.
Ein std::sort ebensowenig ohne operator<.
Wenn deine Klasse also in solchen Situationen verwendet werden soll, ist ein Operator kein Bonus sondern ein Muss.
-
l'abra d'or schrieb:
Wenn deine Klasse also in solchen Situationen verwendet werden soll, ist ein Operator kein Bonus sondern ein Muss.
"Muss" würde ich nicht sagen. Es besteht schliesslich in sehr vielen Fällen die Möglichkeit, Funktionszeiger oder -objekte zu verwenden. Zum Beispiel bei
std::find_if()oder derstd::sort()-Überladung mit Prädikat.Oft ist das sogar sinnvoller, und zwar wenn keine intuitve Konvention für die Operatoren existiert. Also bevor man
operator<für eine Vektorklasse überlädt, sollte man vielleicht über Funktoren/Funktionszeiger nachdenken.
-
Darum hab ich auch geschrieben "verwendet werden soll", es also geplant ist. Dann kann man davon ausgehen, dass ein Vergleich Sinn macht ;).
Da ist es unhandlich, immer ein Prädikat mitzugeben.
-
Okay.
Danke, aber wie ist es, wenn ich Pointerobjekte habe?
Beispiel:X *y = new X; // if (y == y2) // funktioniert nicht, da operator== nicht aufgerufen wirdGruß
-
l'abra d'or schrieb:
Darum hab ich auch geschrieben "verwendet werden soll", es also geplant ist. Dann kann man davon ausgehen, dass ein Vergleich Sinn macht ;).
Okay, ich hab den Satz so verstanden, dass eine Klasse unter anderem in den beschriebenen Situationen verwendet wird. Und lieber einmal ein Operator zu wenig, dafür eine böse Überraschung gespart.

Letztes Mal fand ich übrigens ein schönes Beispiel dafür, wie Operatorüberladung nicht aussehen sollte. Der dortige
operator<taugt nicht mal zur Sortierung in Containern.theliquidwave schrieb:
Danke, aber wie ist es, wenn ich Pointerobjekte habe?
Dann dereferenzierst du sie, wie sonst immer.
-
Nexus schrieb:
Letztes Mal fand ich übrigens ein schönes Beispiel dafür, wie Operatorüberladung nicht aussehen sollte. Der dortige
operator<taugt nicht mal zur Sortierung in Containern.Interessant. Hab gleich mal bei Qt nachgeschaut, und die lassen den operator< bei QVector3D komplett weg

-
Nexus schrieb:
Der dortige
operator<taugt nicht mal zur Sortierung in Containern.Warum?
-
camper schrieb:
Nexus schrieb:
Der dortige
operator<taugt nicht mal zur Sortierung in Containern.Warum?
ich glaub, nexus hat nicht die theoretische seite betrachtet, sondern die praktische^^
es gilt eben für fast jeden vektor x, y:!(x<y) && !(y<x)bb
-
camper schrieb:
Nexus schrieb:
Der dortige
operator<taugt nicht mal zur Sortierung in Containern.Warum?
Man kann diese Version sicherlich als Sortierkriterium im Container verwenden. Aber zusammen mit operator>, operator==, operator!= ergibt sich ein recht komisches Bild, viele Objekte fallen durch das Raster. Und wenn ich eine Möglichkeit biete, Objekte zu vergleichen und zu sortieren, sollte am Ende eine eindeutige Reihenfolge entstehen, und das ist mit dieser Implementierung nicht gegeben.
Außerdem ist die Beschränkung auf die Koordinaten beim Vergleich nicht unbedingt überall angebracht. Ich würde die Vektoren gerne nach Länge sortieren

Wenn ein Sortierkriterium nicht eindeutig gegeben ist, sollte man mMn. auf einen Vergleichsoperator verzichten.
-
camper schrieb:
Nexus schrieb:
Der dortige
operator<taugt nicht mal zur Sortierung in Containern.Warum?
Schau mal das Sortierkriterium an:
inline bool operator < ( const Vector3& rhs ) const { if( x < rhs.x && y < rhs.y && z < rhs.z ) return true; return false; }Nehmen wir zwei Vektoren a = (1,2,4) und b = (2,2,3).
a < bergibtfalse.
b < aergibtfalse.Folglich sind die beiden Vektoren bezüglich des Sortierkriteriums äquivalent. Es besteht kein Strict Weak Ordering. Das macht sich bei assoziativen Containern wie
std::set, die ihre Elemente automatisch sortieren, nicht gut. Hier käme man nicht mal dazu, beide Vektoren einzufügen, obwohl sie unterschiedlich sind.Überhaupt finde ich die gezeigte
Ogre::Vector3-Klasse vom Design und der Implementierung her ziemlich schlecht, aber das ist wieder ein anderes Thema.
-
Nexus schrieb:
Folglich sind die beiden Vektoren bezüglich des Sortierkriteriums äquivalent.
richtig.
Nexus schrieb:
Es besteht kein Strict Weak Ordering.
Kann ich nicht erkennen.
Nexus schrieb:
Das macht sich bei assoziativen Containern wie
std::set, die ihre Elemente automatisch sortieren, nicht gut. Hier käme man nicht mal dazu, beide Vektoren einzufügen, obwohl sie unterschiedlich sind.Zirkelschluss. Äquivalenz wird in diesem Zusammenhang ja gerade erst durch das Sortierkriterium induziert. Die Vektoren sind eben nicht unterschiedlich in diesem Sinne.
Ob das konkrete Kriterium besonders sinnvoll ist, kann dahingestellt bleiben. Jedenfalls würde ich nicht von vornherein ausschließen, dass es Anwendungen für diese Form gibt.
-
Hinzu kommt aber, dass sich die Implementierung inkonsistent bzgl. op > und op == verhält. Und gilt die Äquivalenz zweier Vektoren a und b nun, wenn a == b oder wenn !(a < b) && !(b < a) ?
-
camper schrieb:
Nexus schrieb:
Es besteht kein Strict Weak Ordering.
Kann ich nicht erkennen.
Nicht? Laut Wikipedia muss negative Transitivität für < gelten.
Gegenbeispiel:
Vector3 a(1,2,3); Vector3 b(2,2,4); Vector3 c(4,4,4); a < b; // false b < c; // false a < c; // true, müsste aber false seincamper schrieb:
Zirkelschluss. Äquivalenz wird in diesem Zusammenhang ja gerade erst durch das Sortierkriterium induziert. Die Vektoren sind eben nicht unterschiedlich in diesem Sinne.
Nein, kein Zirkelschluss. Ich bezog "unterschiedlich" auf Gleichheit, nicht Äquivalenz – Gleichheit im Sinne von
operator==, welche auch dem natürlichen Verständnis von Vektorgleichheit entspricht. Ich weiss schon, was du meinst, aber so eine Implementierung macht die Vektorklasse für assoziative Container nicht nur nutzlos, sondern gefährlich. Mehr dazu im unteren Abschnitt.camper schrieb:
Ob das konkrete Kriterium besonders sinnvoll ist, kann dahingestellt bleiben. Jedenfalls würde ich nicht von vornherein ausschließen, dass es Anwendungen für diese Form gibt.
Meinst du? Ich kann es mir schwer vorstellen. Als Anwender erlebt man wahrscheinlich in den meisten Fällen ein blaues Wunder. Ich kann nicht für alle sprechen, aber gerade gestern habe ich relativ lange an einem Fehler gesucht, der von einem falschen Sortierkriterium in meinem Code ausgegangen ist. Wenn man dann hingegen eine fertige Bibliothek anwendet, vertraut man dieser meist ein Stück und sucht den Fehler noch viel eher bei sich. Sowas ist extrem mühsam, das kommt schon fast einem Bug nahe. Und ipsecs Feststellung macht die Situation nicht besser.
Gerade bei Operatoren sollten Entwickler meiner Meinung nach überaus vorsichtig sein. Wenn etwas nicht eindeutig ist, sollte man eher auf benannte Funktionen ausweichen. Es wäre ja kein Problem gewesen, eventuelle Anwendungsfälle mit einer Funktion
ElementwiseLess()oder ähnlich zu berücksichtigen, um alle glücklich zu machen (auch wenn ich sowas nie in eine Vektorklasse packen würde).