2011-01-10 15 views
10

Angenommen, ich bin eine C++ - Bibliothek voller Vererbung gegeben. Ich habe eine Base* in einer Funktion, wenn ich weiß, dass es tatsächlich auf ein Derived Objekt zeigt und Derived erbt Base. Aber ich weiß nicht, welche Art von Vererbung es ist (öffentlich/geschützt/privat). Ich weiß auch nicht, ob es irgendeine virtuelle Funktion in der Hierarchie gibt.static_cast vs dynamic_cast

diese Situation gegeben, ohne den Quellcode/Dokumentation suchen in von Base und Derived, die verwenden werfen sollte ich? Oder sollte ich zuerst den Code/die Dokumentation konsultieren, um Polymorphie zu gewährleisten?

Hintergrund

I 4.7 changeEvent Funktion von QMainWindow in Qt schreibe. Die changeEvent Funktion nimmt QEvent*, die ich auf andere Art durch Wissen QEvent::type() werfen kann. Ich habe mich gefragt, ob ich static_cast oder dynamic_cast verwenden sollte.

Danke.

+3

Wenn eine Bibliothek, die Sie verwenden, eine 'geschützte' Vererbung verwendet, ist es an der Zeit, eine bessere geschriebene Bibliothek zu finden. –

+0

Diese Frage könnte helfen: http://stackoverflow.com/questions/28002/regular-cast-vs-static-cast-vs-dynamic-cast –

+2

@Zac: Ich wünschte, ich könnte Kommentare ablehnen. Wie können Sie möglicherweise beurteilen, ob die geschützte Vererbung das richtige Werkzeug für den Job ist, wenn Sie nicht wissen, was diese Bibliothek tut? – Puppy

Antwort

17

Verwenden Sie static_cast. Wenn Sie wissen, dass Ihre Base* auf eine Derived zeigt, dann verwenden Sie static_cast. dynamic_cast ist nützlich, wenn es könnte zeigen auf eine abgeleitete.

+1

Sie könnten jetzt wissen. Aber er benutzt eine Bibliothek und ich bin mir sicher, dass die Bibliothek keine Garantie dafür gibt, dass sie die Implementierungsdetails nicht ändern werden. Die Schnittstelle ist Base *, also ** ALL ** kann man annehmen. Daher ** ** ** müssen Sie dynamic_cast <> verwenden, damit Sie überprüfen können, ob Ihre Annahmen auch weiterhin gültig sind. –

+0

@Martin: Das ist sein Problem, nicht meins. Wenn er * weiß *, dass es tatsächlich auf ein Abgeleitetes hinweist, dann liegt die Wurzel dieses Wissens außerhalb der Grenzen dessen, was ich möglicherweise beantworten kann. – Puppy

+2

Das Problem ist, er kann es nicht wissen. Sein Wissen ist auf den Zeitbereich begrenzt, der für diesen einen bestimmten Fall wichtig ist. Daher müssen wir betonen, dass das OP in seiner Annahme falsch ist, dass er es weiß. Er weiß es jetzt, aber das Wissen ist nicht auf die Zukunft übertragbar. Also, weil er falsch ist, ist static_cast die falsche Antwort (es ist die richtige Antwort, wenn das OP korrekt war (aber er ist nicht)). Die einzige Zeit, von der Sie annehmen können, dass die Schnittstelle abgeleitet ist, ist, wenn sie eine abgeleitete * gibt, andernfalls kann sie alles zurückgeben, das von Base * abgeleitet wurde (deshalb haben wir Schnittstellen im Code). –

3

Von MSDN -

Im Allgemeinen verwenden Sie static_cast wenn Sie numerische Datentypen wie Aufzählungen zu ints oder ints Schwimmer konvertieren wollen, und Sie sind sicher der Datentypen in der Umsetzung beteiligt. static_cast-Konvertierungen sind nicht so sicher wie dynamic_cast-Konvertierungen, da static_cast keine Laufzeittypprüfung durchführt, während dynamic_cast dies tut. Ein dynamic_cast zu einem mehrdeutigen Zeiger schlägt fehl, während ein static_cast zurückkehrt, als ob nichts falsch wäre. Das kann gefährlich sein. Obwohl dynamic_cast-Konvertierungen sicherer sind, funktioniert dynamic_cast nur für Zeiger oder Verweise, und die Laufzeittypüberprüfung ist ein Overhead.

Für weitere Informationen, lesen Sie in diesem link

8

Im Zweifelsfall sollten Sie dynamic_cast bevorzugen. Es könnte langsamer sein, aber Sie werden wahrscheinlich den Unterschied sowieso nicht bemerken.

Wenn Sie Geschwindigkeit benötigen, verwenden Sie den folgenden Code-Schnipsel:

template <typename Derived, typename Base> 
Derived safe_static_cast(Base b) 
{ 
    assert((void*)dynamic_cast<Derived>(b) && "safe_static_cast failed!"); 
    return static_cast<Derived>(b); 
} 

oder etwas Gleichwertiges.

Die Idee ist, dass in Debug-Builds überprüft, dass es in der Tat ist, was Sie dachten, und es Releases Builds ... nun, alles wurde bereits getestet, oder?

+1

Sie brauchen nicht '(void *)' Besetzung –

+0

@Gene: es ist zugegebenermaßen hässlich :) Ich habe versucht, Überlastung für den Referenzfall zu vermeiden. –

Verwandte Themen