Virtuelle Funktion wird verdeckt!
-
[Doppelt gepostet]
-
class base
{
// ...
friend base;
// ...
};Was soll das?
Und wie würdest du denn den Vergleichsoperator implementieren?
Einen virtuellen Vergleichsoperator in der Basisklasse + zwei Vergleichsoperatoren in jeder abgeleiteten Klasse. Einer überschreibt den der Basisklasse und einer für den nicht virtuellen Vergleich:
class Base { int i_; public: Base(int i) : i_(i) {} virtual bool operator==(const Base& rhs) const { return i_ == rhs.i_; } }; class Derived : public Base { private: int j_; public: Derived(int i, int j) : Base(i), j_(j) {} bool operator==(const Base& rhs) const { if (const Derived* p = dynamic_cast<const Derived*>(&rhs)) { return j_ == p->j_ && Base::operator==(rhs); } return false; } bool operator==(const Derived& rhs) const { return j_ == rhs.j_ && Base::operator==(rhs); } }; int main() { Derived d1(1,2); Derived d2(2,2); Base& rd1 = d1; Base& rd2 = d2; d1 == d2; // Derived::operator==(const Derived&) rd1 == rd2; // Derived::operator==(const Base&) Base b1(1); Base b2(2); b1 == b2; // Base::operator==(const Base&) rd1 == b1; // Derived::operator==(const Base&) }
-
Warum lässt sich denn sowas dann überhaupt übersetzen?
übersetzen lässt sich vieles:) wobei es natürlich in der Regel ohne das virtual richtig laufen würden, aber halt nur in der Regel..
-
@all:
Danke für eure Antworten!@Hume:
Gut, ist ne Lösung. Danke!
Ich war mir nur nicht so ganz sicher, ob auch eine Lösung ohne DownCast existiert. Das Thema mit den DownCasts hatten wir ja schon oft. Geht aber offensichtlich nicht anders. Die Kröte muss man wohl schlucken! :pAch übrigens:
Es wurde zwar schon freundlicherweise eine Antwort auf die Frage gepostet, warum das oben genannte Codebeispiel auch ohne 'virtual' übersetzt werden kann, aber vielleicht kannst mir ja Du damit noch etwas auf die Sprünge helfen. Wie kann denn eine Deklaration in der genannten Form ohne 'virtual' wirklich Sinn ergeben?
Das ist mir ehrlich gesagt noch nicht so ganz klar!Danke!
Grüße,
TS++
-
Faustregel:
Virtuell sollte in der Regel alle Methoden (und Operatoren) sein, von denen
du annimmst, dass sie in darunter liegenden Klassen überladen werden. Der
Nachteil in virtuellen Methoden liegt allerdings darin, dass sie durch die
dynamische Bindung an das Objekt langsamer laufen, daher sollte man sich
auch auf die oben genannten beschränken.
-
Eine virtuele Methode ist nix anderes als ne Funktion wo die C++ Sprache direkt weiss was es für ein objekt ist ... warte ich erklär das mal schnell!
also zB ich hab eine Klasse CStaatsanwalt und ne Klasse CRichter
*GG* und ich sage dann CStaatsanwalt ist ne virtuele Klasse von CRichter da CRichter ja auch ne Funktion hat die in CStaatsanwalt drinne ist (sprechen, reden, anklagen etc. du weißt was ich meine) und damit C++ weiss woran es dir liegt must du sagen CStaatswanalt ist virtuel damit es auch richtig geht muss auch CRichter dann nur public benutzen!
Aber Visual C++ hat nen problem damit. es geht nur mit WinAPI oder mit normalem C++.
-
Eine virtuele Methode ist nix anderes als ne Funktion wo die C++ Sprache direkt weiss was es für ein objekt ist ... warte ich erklär das mal schnell!
also zB ich hab eine Klasse CStaatsanwalt und ne Klasse CRichter
*GG* und ich sage dann CStaatsanwalt ist ne virtuele Klasse von CRichter da CRichter ja auch ne Funktion hat die in CStaatsanwalt drinne ist (sprechen, reden, anklagen etc. du weißt was ich meine) und damit C++ weiss woran es dir liegt must du sagen CStaatswanalt ist virtuel damit es auch richtig geht muss auch CRichter dann nur public benutzen!
Aber Visual C++ hat nen problem damit. es geht nur mit WinAPI oder mit normalem C++.
-
Mit Humes Base und Derived:
bool compare( const Base &lhs, const Base &rhs) { return lhs == rhs; } int main() { Derived d(42, 4711); Base b(42); assert(compare(d, b) == compare(b, d)); // Peng! }
Ich bezweifle stark, daß das Sinn macht! Ein virtueller operator==() wird vermutlich mehr schaden als nützen.
Stefan.
-
DStefan schrieb:
Mit Humes Base und Derived:
Ich bezweifle stark, daß das Sinn macht! Ein virtueller operator==() wird vermutlich mehr schaden als nützen.jo, scheint mir auch.
also man darf schonmal nicht die rechte seite hochcasten, bis sie paßt, sie beliebig viel ballast abwerfen lassen und dann vergleichen.
die beiden dürfen nur gleich sein, wenn sie genau der selben klasse angehören.bool operator==(Base const& a,Base const& b) { if(typeid(a)!=typeid(b)) return false; if(!a.compare(b)) return false; return true; }
kommt man hier auch billig ohne rtti weg?
-
Ich bezweifle stark, daß das Sinn macht! Ein virtueller operator==() wird vermutlich mehr schaden als nützen.
Ich zweifle ebenfalls an dem Sinn. Ich wollte hier aber nicht über Sinn oder Unsinn diskutieren.
Ich umgehe dieses Problem in der Regel dadurch, dass ich nur Value-Objekte mit dem op== vergleiche. Von diesen leitet man nicht ab und wenn, dann vergleicht man sie nicht polymporph. Insofern benutze ich weder virtuelle Vergleichsoperatoren noch virtuelle Zuweisungen.
also man darf schonmal nicht die rechte seite hochcasten, bis sie paßt, sie beliebig viel ballast abwerfen lassen und dann vergleichen.
die beiden dürfen nur gleich sein, wenn sie genau der selben klasse angehören.Man muss halt dafür sorgen, dass der Vergleich den Bedingungen einer Äquivalenzrelation genügt (Reflexiv, Symetrisch, Transitiv) und konsistent ist (ein wiederholter Vergleich liefert immer das gleiche Ergebnis, solange die beteiligten Objekte nicht veränert wurden).
Meine Variante ist offensichtlich nicht symetrisch.Ein Vergleich, der Teilobjekt-Vergleiche (slice-comparison) erlaubt, kann auf der anderen Seite niemals Transitiv sein.
Will man also unbedingt einen virtuellen op==, dann muss man bereits in der Basisklasse dafür sorgen, dass keine Teilobjekt-Vergleiche durchgeführt werden, dass also immer nur Objekte von exakt der gleichen Klasse verglichen werden. Um ein typeid (wie in volkards Lösung) kommt man nicht herum.
Hat man einmal in der Hierarchie nur einen halbseitigen Test mit dem dynamic_cast drin (so wie bei mir), kann man die Symetrie-Bedingung nicht mehr erfüllen.PS: Wer das Ganze etwas ausführlicher haben will, sollte den folgenden Artikel lesen:
http://www.cuj.com/documents/s=8467/cujjsup2004langer/Da geht's zwar um Javas equals, das Prinzip trifft aber auch auf C++ zu.
-
Lustig. Gerade laufe ich mal schnell runter zur Fluppenkiste. Schau auf dem Rückweg in den Briefkasten, fische die aktuelle Ausgabe des Dr. Dobb's Journal raus und was finde ich darin?
Richtig: Einen Artikel mit dem Titel: "Overriding the C++ Operator=="
Muss ich doch gleich mal lesen...
-
TS++ schrieb:
Hallo Bashar!
Ich hab grad mal aus lauter Verzweiflung 'virtual' rausgeschmissen. Und was soll ich dir sagen: es funktioniert!
Das verwirrt mich jetzt doch etwas! Wieso ist denn sowas erlaubt? Ich hätte instinktiv niemals etwas derartiges programmiert!
Vielleicht kannst du mir ja helfen!Danke!
Grüße,
TS++<imho>Dann dürfte die aber noch trotzdem überdeckt werden, du willst eine Überladung, dann brauchst du aber noch ein
using base::method;
davor.</imho>Lars
-
volkard schrieb:
kommt man hier auch billig ohne rtti weg?
Ich denke nicht. Das läßt sich im allgemeinen als Double-Dispatch bezeichnen. C++ kennt aber nur Single-Dispatch.
Einfach mal nachgooglen, wenn jemand mit den Begriffen nichts anfangen kann...
-
@volkard:
Ich glaube, du bist zu streng. Dein operator verlangt zwei Base und sollte sich meiner Meinung nach nicht darum scheren, ob seine Argumente "in Wirklichkeit" Unterklassen sind. Die Funktion sollte true liefern, wenn die Base-Anteile der Objekte gleich sind und Schluß.Ich gebe zu, daß es mir schwer fällt zu erklären, warum ich dieser Meinung bin. Im Moment fühlt sich das einfach nur richtig an.
Vielleicht könnte man so sagen: Die Umgebung, in der dieser Vergleich stattfindet, wird wohl eine Base-Umgebung sein. Wenn Base Unterklassen hat, gibt es diese Base Umgebung als eine Art Framework für alles, was man mit Base machen kann. Ich unterstelle, daß dieses Framework per Design so geschaffen ist. Ein Test auf Gleichheit zweier Base _muß_ dann true liefern, falls der Base-Anteil der Objekte gleich ist, denn ich glaube, daß ein solches Framework anders gar nicht (richtig) funktionieren kann. Ein Test auf den _Wert_ eines Objekts sollte nicht vom _Typ_ des Objekts abhängen. Mit ist so, als würde ansonsten der Polymorphismus seine Unschuld verlieren.
Ich habe bisher noch nie mit virtuellen operator==() experimentiert. Vielleicht ist dieser Beitrag deshalb ein bischen schwammig......
Stefan.
-
Das würde ja bedeuten, dass ein Hund gleich einem Pinguin ist, wenn sie gleich alt sind?
-
Das würde ja bedeuten, dass ein Hund gleich einem Pinguin ist, wenn sie gleich alt sind?
Nein, das würde bedeuten, daß zwei _Tiere_ gleich sind, wenn sie gleich alt sind. Und das unabhängig davon, ob es nun Hunde oder Pinguine sind. Das habe ich mit diesem Begriff "Framework für Base" gemeint. Im Kontext des operator==(const Tier&, const Tier&) gibt es weder Hunde noch Pinguine, bloß Tiere.
Stefan.
-
Fazit:
Die Implementierung ist Kontexabhängig.
-
Scheiss neues Forum, immer wieder ausgeloggt.
-
Ich hab dich schon verstanden, ich finde es nur sinnlos, dass du dem Vergleichsoperator willkürlich einen solchen eingeschränkten Kontext geben willst.
Hund h("Collie", 42); Pinguin p(42); assert(h == p);
finde ich fragwürdig.
-
Hund h("Collie", 42);
Pinguin p(42);
assert(h == p);C/C++ Code:
.........finde ich fragwürdig.
Sehe ich genau so.