Ich bin ziemlich verwirrt mit dem dynamic_cast
Schlüsselwort in C ++.
struct A {
virtual void f() { }
};
struct B : public A { };
struct C { };
void f () {
A a;
B b;
A* ap = &b;
B* b1 = dynamic_cast<B*> (&a); // NULL, because 'a' is not a 'B'
B* b2 = dynamic_cast<B*> (ap); // 'b'
C* c = dynamic_cast<C*> (ap); // NULL.
A& ar = dynamic_cast<A&> (*ap); // Ok.
B& br = dynamic_cast<B&> (*ap); // Ok.
C& cr = dynamic_cast<C&> (*ap); // std::bad_cast
}
Die Definition lautet:
Das
dynamic_cast
Schlüsselwort wandelt ein Datum von einem Zeiger oder Referenztyp in einen anderen um und führt eine Laufzeitprüfung durch, um die Gültigkeit der Umwandlung sicherzustellen
Können wir ein Äquivalent von dynamic_cast
C ++ in C schreiben , damit ich die Dinge besser verstehen kann?
c++
dynamic-cast
Vijay
quelle
quelle
dynamic_cast<>
hinter den Kulissen funktioniert (oder wie viel von C ++ funktioniert), ist Lippmans "Inside the C ++ Object Model" ein gutes Buch (das auch für etwas so Technisches ziemlich einfach zu lesen ist). Auch Stroustrups Bücher "Design and Evolution of C ++" und "The C ++ Programming Language" sind gute Ressourcen, aber Lippmans Buch widmet sich der Funktionsweise von C ++ "hinter den Kulissen".B* b2 = dynamic_cast<B*> (ap) // 'b'
?b2 is pointer to b
oder was?Antworten:
Hier ist ein Überblick über
static_cast<>
unddynamic_cast<>
speziell in Bezug auf Zeiger. Dies ist nur ein Überblick über 101 Ebenen, der nicht alle Feinheiten abdeckt.static_cast <Typ *> (ptr)
Dadurch wird der Zeiger aufgenommen
ptr
und versucht, ihn sicher in einen Zeiger vom Typ umzuwandelnType*
. Diese Umwandlung erfolgt zur Kompilierungszeit. Die Umwandlung wird nur durchgeführt, wenn die Typtypen verwandt sind. Wenn die Typen nicht verwandt sind, wird ein Compilerfehler angezeigt. Beispielsweise:dynamic_cast <Typ *> (ptr)
Dies versucht erneut, den Zeiger aufzunehmen
ptr
und sicher in einen Zeiger vom Typ umzuwandelnType*
. Diese Umwandlung wird jedoch zur Laufzeit und nicht zur Kompilierungszeit ausgeführt. Da es sich um eine Laufzeitumwandlung handelt, ist sie insbesondere in Kombination mit polymorphen Klassen nützlich. In der Tat, in certian Fällen die Klassen müssen polymorph sein , um für die Besetzung legal.Casts können in eine von zwei Richtungen gehen: von Basis zu abgeleitet (B2D) oder von abgeleitet zu Basis (D2B). Es ist einfach genug zu sehen, wie D2B-Casts zur Laufzeit funktionieren würden. Entweder
ptr
wurde abgeleitet vonType
oder es war nicht. Bei D2B dynamic_cast <> s sind die Regeln einfach. Sie können versuchen, alles in etwas anderes umzuwandeln, und wennptr
es tatsächlich von abgeleitet wurdeType
, erhalten Sie einenType*
Zeiger zurück vondynamic_cast
. Andernfalls erhalten Sie einen NULL-Zeiger.B2D-Casts sind jedoch etwas komplizierter. Betrachten Sie den folgenden Code:
main()
Ich kann nicht sagen, welche Art von Objekt zurückgegebenCreateRandom()
wird, daher ist die Besetzung im C-StilBar* bar = (Bar*)base;
definitiv nicht typsicher. Wie können Sie das beheben? Eine Möglichkeit wäreAreYouABar() const = 0;
, der Basisklasse eine Funktion wie bool hinzuzufügen undtrue
vonBar
undfalse
nach zurückzukehrenFoo
. Aber es gibt noch einen anderen Weg: Verwenden Siedynamic_cast<>
:Die Casts werden zur Laufzeit ausgeführt und arbeiten, indem sie das Objekt abfragen (Sie müssen sich vorerst keine Gedanken darüber machen, wie) und fragen, ob es der Typ ist, nach dem wir suchen. Wenn dies der Fall ist, wird
dynamic_cast<Type*>
ein Zeiger zurückgegeben. Andernfalls wird NULL zurückgegeben.Damit dieses Casting von Basis zu Basis funktioniert
dynamic_cast<>
, müssen Base, Foo und Bar das sein, was der Standard als polymorphe Typen bezeichnet . Um ein polymorpher Typ zu sein, muss Ihre Klasse mindestens einevirtual
Funktion haben. Wenn Ihre Klassen keine polymorphen Typen sind, wird die Verwendung von Basis zu Ableitung vondynamic_cast
nicht kompiliert. Beispiel:Durch Hinzufügen einer virtuellen Funktion zur Basis, z. B. eines virtuellen Dtors, werden sowohl die Basis- als auch die Der-Polymorph-Typen erstellt:
quelle
Base* base = new Base;
,dynamic_cast<Foo*>(base)
wirdNULL
.dynamic_cast<Foo*>(base)
ist das bei a nullBase* base = new Base;
?base
ist nicht einFoo
. EinBase
Zeiger kann auf a zeigenFoo
, aber es ist immer noch aFoo
, sodass eine dynamische Besetzung funktioniert. Wenn Sie dies tunBase* base = new Base
,base
ist aBase
, nicht aFoo
, sodass Sie es nicht dynamisch in a umwandeln könnenFoo
.Es ist nicht möglich,
dynamic_cast
direkt in C ++ - Code auf Benutzerebene zu implementieren, es sei denn, Sie implementieren Ihre eigene handgerollte RTTI (und umgehen die System-RTTI) .dynamic_cast
ist stark mit dem RTTI-System der C ++ - Implementierung verbunden.Um Ihnen jedoch zu helfen, RTTI (und damit
dynamic_cast
) besser zu verstehen , sollten Sie den<typeinfo>
Header und dentypeid
Operator nachlesen . Dies gibt die Typinformationen zurück, die dem Objekt entsprechen, das Sie zur Hand haben, und Sie können verschiedene (begrenzte) Dinge von diesen Typinfoobjekten abfragen.quelle
dynamic_cast
sind sehr knapp. :-P Spielen Sie einfach selbst damit, bis Sie den Dreh raus haben. :-)Mehr als Code in C denke ich, dass eine englische Definition ausreichen könnte:
Bei einer Klassenbasis, von der eine abgeleitete Klasse abgeleitet ist,
dynamic_cast
wird ein Basiszeiger genau dann in einen abgeleiteten Zeiger konvertiert, wenn das tatsächliche Objekt, auf das gezeigt wird, tatsächlich ein abgeleitetes Objekt ist.Im Beispiel
test
bindet der Aufruf zum Binden verschiedener Objekte an einen Verweis aufBase
. Intern wird die Referenz downcasted einen Verweis aufDerived
eine typsichere Art und Weise: die niedergeschlagenen wird nur gelingen , für jene Fälle , in denen das referenzierte Objekt ist in der Tat eine InstanzDerived
.quelle
Das Folgende kommt dem, was Sie von C ++
dynamic_cast
in Bezug auf die Typprüfung erhalten, nicht wirklich nahe, aber vielleicht hilft es Ihnen, den Zweck ein wenig besser zu verstehen:quelle
A
dynamic_cast
führt eine Typprüfung mit RTTI durch . Wenn es fehlschlägt, wird eine Ausnahme ausgelöst (wenn Sie ihm eine Referenz gegeben haben) oder NULL, wenn Sie ihm einen Zeiger gegeben haben.quelle
Um die dynamische Umwandlung in C-Begriffen zu beschreiben, müssen wir zunächst Klassen in C darstellen. Klassen mit virtuellen Funktionen verwenden eine "VTABLE" von Zeigern auf die virtuellen Funktionen. Kommentare sind C ++. Fühlen Sie sich frei, Kompilierungsfehler neu zu formatieren und zu beheben ...
Dann ist eine dynamische Besetzung so etwas wie:
quelle
In C gibt es keine Klassen, daher ist es unmöglich, dynamic_cast in dieser Sprache zu schreiben. C-Strukturen haben keine Methoden (daher haben sie keine virtuellen Methoden), daher ist nichts "Dynamisches" darin.
quelle
Nein, nicht leicht. Der Compiler weist jeder Klasse eine eindeutige Identität zu. Diese Informationen werden von jeder Objektinstanz referenziert. Diese Informationen werden zur Laufzeit überprüft, um festzustellen, ob eine dynamische Umwandlung zulässig ist. Sie könnten eine Standardbasisklasse mit diesen Informationen und Operatoren erstellen, um die Laufzeitprüfung für diese Basisklasse durchzuführen. Dann würde jede abgeleitete Klasse die Basisklasse über ihren Platz in der Klassenhierarchie informieren und alle Instanzen dieser Klassen könnten über zur Laufzeit umgewandelt werden Ihre Operationen.
bearbeiten
Hier ist eine Implementierung, die eine Technik demonstriert. Ich behaupte nicht, dass der Compiler so etwas verwendet, aber ich denke, es demonstriert die Konzepte:
quelle
dynamic_cast verwendet RTTI. Es kann Ihre Anwendung verlangsamen, können Sie Änderung des Besuchers Entwurfsmuster verwenden , um zu erreichen einziehe ohne RTTI http://arturx64.github.io/programming-world/2016/02/06/lazy-visitor.html
quelle
static_cast< Type* >(ptr)
static_cast in C ++ kann in Szenarien verwendet werden, in denen alle Typumwandlungen zur Kompilierungszeit überprüft werden können .
dynamic_cast< Type* >(ptr)
dynamic_cast in C ++ kann verwendet werden, um typsicheres Downcasting durchzuführen . dynamic_cast ist Laufzeitpolymorphismus. Der Operator dynamic_cast, der sicher von einem Zeiger (oder einer Referenz) in einen Basistyp in einen Zeiger (oder eine Referenz) in einen abgeleiteten Typ konvertiert.
zB 1:
Für weitere Informationen klicken Sie auf hier
zB 2:
quelle