Überladen von Operatoren + Vererbung
-
Hallo,
Ich möchte Folgendes bewerkstelligen: Ich habe eine Interface-Klasse:
class A { virtual bool operator==(const A &a) = 0; }Jetzt sollen von A abgeleitete Klassen den Operator implemenieren, z.B.:
class B : public A { int i; virtual bool operator==(const A &a) { B b = (A)a; // Casten return i == b.i; }; }Im Programm selber wird dann sowas gemacht:
A c1 = B(); A c2 = B(); if (c1 == c2) ...Das funktioniert auch soweit, nur muss ich innerhalb des Operators casten. Gibt es eien Möglichkeit mit dem Interface zu arbeiten, und trotzdem das Casten zu vermeiden (aus Performancegründen)? Also z.B. irgendwie so (wenn ich das so mache, dann schreit der Compiler natürlich, dass der Operator für "A" nicht implementiert wurde):
class B : public A{ virtual bool operator==(const B &a) { ... } }Ich hoffe, es ist verständlich was ich möchte.

Grüße,
-
pixsta schrieb:
Ich möchte Folgendes bewerkstelligen: Ich habe eine Interface-Klasse:
class A { virtual bool operator==(const A &a) = 0; }Besser:
virtual bool operator==(const A &a) const = 0;Aber brauchst Du wirklich diese Art von Polymorphie? (Frage soll zum Nachdenken anregen)
pixsta schrieb:
Jetzt sollen von A abgeleitete Klassen den Operator implemenieren, z.B.:
class B : public A { int i; virtual bool operator==(const A &a) { B b = (A)a; // Casten return i == b.i; }; }

Das kompiliert ja nicht einmal. Du meintest wahrscheinlich "B b = (B)a;". Das kompiliert aber genauso wenig! Wir sind hier nicht im Java-Land.Besser:
B const& b = dynamic_cast<B const&>(a);
Die Zeile wirft eine Ausnhame, falls "a kein B war".pixsta schrieb:
Das funktioniert auch soweit, nur muss ich innerhalb des Operators casten. Gibt es eien Möglichkeit mit dem Interface zu arbeiten, und trotzdem das Casten zu vermeiden (aus Performancegründen)?
Nein. Du kannst dynamic_cast noch durch static_cast ersetzten, wenn Du Dir wirklich ganz sicher bist, dass der "Cast" auch legal ist. Es könnte dann etwas schneller sein, führt aber, wenn Du den Compiler belügst und a keine Referenz auf ein B-Objekt ist, zu undefiniertem Verhalten.
pixsta schrieb:
Also z.B. irgendwie so (wenn ich das so mache, dann schreit der Compiler natürlich, dass der Operator für "A" nicht implementiert wurde):
class B : public A{ virtual bool operator==(const B &a) { ... } }Nö, das ist dann eine neue virtuelle Funktion.
Du nutzt für Dein Problem die falschen Sprachmittel und/oder wendest sie falsch an.
Gruß,
SP
-
(aus Performancegründen)
Hast du gemessen, wieviel Zeit es kostet. Ich denke nicht, dass daraus ein Performanceproblem entsteht.
Und: Das, was du machst, ist boese! Eine andere Klasse C abgeleitet von A kann auch einen Vergleichsoperator definieren. Und dann testest du z.B. B == C, was aber durchaus ein anderes Ergebnis liefern kann als C == B (je nach Implementation). Auch ist es sehr fraglich, was C == B zu bedeuten hat. Da kann man durchaus ein Schwein auf Gleichheit mit einem Pferd vergleichen wenn die Basisklasse Tier ist und true erhalten. Das ist sinnbefreit.
virtual bool operator==(const A &a) { B b = (A)a; // Casten return i == b.i;}Das darfst du so nicht casten! Da nicht jedes A unbedingt ein B ist. Auch verletzt es den Vertrag gegeben durch die Signatur. Das Substitutionsprinzip ist auch verletzt. ...
-
Danke für die Tipps. Ich werde mich noch etwas herumspielen - vielleicht geht's ja auch ohne casten.
-
pixsta schrieb:
Danke für die Tipps. Ich werde mich noch etwas herumspielen - vielleicht geht's ja auch ohne casten.
Das ist nicht das Problem! Den Vergleichsoperator virtuell machen ist das Problem.
-
Performanceverlust brauchst Du nur beim dynamic_cast zu befürchten.
static_cast auf Zeiger und Referenzen ist kostenlos.Aber Du hast doch erlaubt, daß man Basisklassenreferenzen benutzt. Es kann nicht sein, daß zwei Vögel gleicher Masse als gleich gelten, obwohl der Singvogel eine andere Melodie hat als dem Raubvogel sein Lieblingsfressen. Also muß der Vergleich auf jeden Fall von den konkreten geerbten Klassen getutet werden. Dahin können wir fein mit virtuellen Funktionen gehen.
bool ::operator==(Base &a,Base& b) { return a.equals(b); }Jetzt hat Klasse A den schwarzen Peter. Mal sehen, wie sie damit umgeht.
bool A::equals(Base& b) { if(typeid(*this)!=typeid(b)) return false;//Ein Specht ist kein Kolibri, //und wenn sie sich auch noch so ähnlich sind und diese beiden sogar //gleich schnell fliegen und das gleiche essen. A& other=static_cast<A&>(b);//klappt sogar manchmal if(name!=other.name) return false; if(melodie!=other.melodie) return false; return true; }Vielleicht hilft das für deine weiteren Forschungen.
Aber das Kernproblem ist, daß man glaub ich gar keinen operator== für Interfaces brauchen kann.
-
zu den oben angeführten Ausbesserungen (nachdem jetzt einige Kommentare wegen meiner unklaren [vielleicht unsinnigen] Frage vom Thema abgekommen sind):
ich habe den Code hier nur zusammen gefasst. Bei dem "Working-Code" wird natürlich richtig gecasted (static) und auch die Operatoren geben "const bool" zurück. Mir ging es bei meiner Frage ja auch nicht darum, sondern eben um diese "Vererbung" von Operatoren.Was passiert ist folgendes: es gibt eine Auswahl von Klassen die von A abgeleitet sind, und eine dieser Klassen kann während der Laufzeit ausgewählt werden. Jede dieser Klassen hat unterschiedliche Parameter die im Operator "==" verglichen werden sollen.
Aus meiner Sicht geht das offensichtlich nur, indem man eine eigene Funktion definiert:
class A { virtual bool equal(const A &a) {...}; bool operator==(const A &a) { return equal(a); } } class A : public B { virtual bool equal(const A &a) { // casten, etc. ...}; }
-
volkard schrieb:
Performanceverlust brauchst Du nur beim dynamic_cast zu befürchten.
static_cast auf Zeiger und Referenzen ist kostenlos.Aber Du hast doch erlaubt, daß man Basisklassenreferenzen benutzt. Es kann nicht sein, daß zwei Vögel gleicher Masse als gleich gelten, obwohl der Singvogel eine andere Melodie hat als dem Raubvogel sein Lieblingsfressen. Also muß der Vergleich auf jeden Fall von den konkreten geerbten Klassen getutet werden. Dahin können wir fein mit virtuellen Funktionen gehen.
bool ::operator==(Base &a,Base& b) { return a.equals(b); }Jetzt hat Klasse A den schwarzen Peter. Mal sehen, wie sie damit umgeht.
bool A::Equals(Base& b) { if(typeid(*this)!=typeid(b)) return false;//Ein Specht ist kein Kolibri, //und wenn sie sich auch noch so ähnlich sind und diese beiden sogar //gleich schnell fliegen und das gleiche essen. if(name!=b.name) return false; if(melodie!=b.melodie) return false; return true; }Vielleicht hilft das für deine weiteren Forschungen.
Aber das Kernproblem ist, daß man glaub ich gar keinen operator== für Interfaces brauchen kann.
Danke.
P.S: mein letztes Post habe ich geschrieben während du gepostet hast - daher die ähnliche Idee...
-
EDIT: hat sich erübrigt.