2017-09-24 2 views
0

Wie erstellt man eine effiziente Methode equals für abgeleitete Klassen?Wie wird der Gleichheitstest für abgeleitete Klassen durchgeführt?

struct Base { 
    virtual bool equals(const Base &other) const = 0; 
}; 

Die übliche Antwort ist dynamic_cast oder typeid verwenden Art Identität in abgeleiteten Klassen zu überprüfen, und wenn Typ übereinstimmt, dann kann ein Vergleich:

struct Derived: Base { 
    virtual bool equals(const Base &other) const override { 
     if (typeid(*this)!=typeid(other)) return false; 

     return *this==static_cast<Derived &>(other); 
    } 
}; 

Gibt es eine effizientere Möglichkeit, diese Art zu tun prüfen? Was können wir tun, wenn RTTI deaktiviert ist?

+0

Wenn Sie bereit sind, gegen das Liskov-Substitutionsprinzip zu verstoßen (dies führt zu anderen Kompromissen, die für Sie akzeptabel oder nicht akzeptabel sind), verwenden Sie den doppelten Versand. – Peter

+0

@Peter: meinst du eine Lösung, wo alle abgeleiteten Typen in irgendeiner Form aufgelistet werden müssen? – geza

+0

Nun, ja. Wenn Sie ein Verhalten wünschen, das vom Typ abhängt, ohne den Typ (oder die Typ-ID) zu testen, müssen Sie für jeden wichtigen Typ etwas Bestimmtes tun. – Peter

Antwort

0

Ich habe noch nie diesen „Trick“ gesehen, also werde ich es hier hinzufügen:

struct Base { 
    virtual bool equals(const Base &other) const = 0; 

    virtual const void *typeMarker() const = 0; 
}; 

struct Derived: public Base { 
    static char s_typeMarker; 

    virtual bool equals(const Base &other) const override { 
     if (&s_typeMarker!=other.typeMarker()) return false; 

     return *this==static_cast<Derived &>(other); 
    } 

    virtual const void *typeMarker() const override { 
     return &s_typeMarker; 
    } 
}; 

Grundsätzlich hat es eine typeMarker() virtuelle Funktion, die für jeden Typ einen eindeutigen Wert zurückgibt. Also, Typ Gleichheitsprüfung erfolgt mit einem virtuellen Funktionsaufruf (und einem Vergleich), die billiger sein kann als typeid oder dynamic_cast, und diese Methode funktioniert mit RTTI deaktiviert.

Der einzige Nachteil, den ich kenne, ist, dass dies nicht über .dlls funktioniert.

(zu dieser Antwort Basierend kann vielleicht jemand mit einer besseren Lösung kommen.)

1

Ich denke, das Kernproblem ist, dass Sie nicht Typen vergleichen müssen sollen. Dieses Bedürfnis zeigt immer ein schlechtes Design, eine falsche Verwendung der Vererbung oder andere schlechte Muster.

Schauen Sie, warum Sie die Gleichheitsinformationen benötigen - was werden Sie damit machen nächste, die Sie nicht durch Aufruf einer vererbten und überschriebenen Methode der Klassen tun konnten?

+0

Im Allgemeinen stimme ich Ihnen zu. Aber es kann Fälle geben, in denen diese Funktionalität nützlich ist. Beispielsweise ein Element aus einem Container nach Wert entfernen. Für Typen ohne 'operator == 'kann dies nur mit einer Art von Token implementiert werden (add gibt ein Token zurück, das beim Entfernen verwendet werden kann). – geza

+0

Dieses Problem tritt auf, wenn Sie Multicast-Funktionen implementieren möchten [Herb Sutter spricht darüber] (http://www.drdobbs.com/cpp/generalizing-observer/184403873). Leider, wie sich herausstellte, können aktuelle C++ Lamba's auch nicht mit Gleichheit verglichen werden, daher kann dies mit dem aktuellen C++ ohne Verwendung von Token nicht durchgeführt werden. – geza

Verwandte Themen