Hier ist ein Überblick über static_cast<>
und dynamic_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 umzuwandeln Type*
. 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:
class B {};
class D : public B {};
class X {};
int main()
{
D* d = new D;
B* b = static_cast<B*>(d); // this works
X* x = static_cast<X*>(d); // ERROR - Won't compile
return 0;
}
dynamic_cast <Typ *> (ptr)
Dies versucht erneut, den Zeiger aufzunehmen ptr
und sicher in einen Zeiger vom Typ umzuwandeln Type*
. 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 von Type
oder es war nicht. Bei D2B dynamic_cast <> s sind die Regeln einfach. Sie können versuchen, alles in etwas anderes umzuwandeln, und wenn ptr
es tatsächlich von abgeleitet wurde Type
, erhalten Sie einen Type*
Zeiger zurück von dynamic_cast
. Andernfalls erhalten Sie einen NULL-Zeiger.
B2D-Casts sind jedoch etwas komplizierter. Betrachten Sie den folgenden Code:
#include <iostream>
using namespace std;
class Base
{
public:
virtual void DoIt() = 0; // pure virtual
virtual ~Base() {};
};
class Foo : public Base
{
public:
virtual void DoIt() { cout << "Foo"; };
void FooIt() { cout << "Fooing It..."; }
};
class Bar : public Base
{
public :
virtual void DoIt() { cout << "Bar"; }
void BarIt() { cout << "baring It..."; }
};
Base* CreateRandom()
{
if( (rand()%2) == 0 )
return new Foo;
else
return new Bar;
}
int main()
{
for( int n = 0; n < 10; ++n )
{
Base* base = CreateRandom();
base->DoIt();
Bar* bar = (Bar*)base;
bar->BarIt();
}
return 0;
}
main()
Ich kann nicht sagen, welche Art von Objekt zurückgegeben CreateRandom()
wird, daher ist die Besetzung im C-Stil Bar* bar = (Bar*)base;
definitiv nicht typsicher. Wie können Sie das beheben? Eine Möglichkeit wäre AreYouABar() const = 0;
, der Basisklasse eine Funktion wie bool hinzuzufügen und true
von Bar
und false
nach zurückzukehren Foo
. Aber es gibt noch einen anderen Weg: Verwenden Sie dynamic_cast<>
:
int main()
{
for( int n = 0; n < 10; ++n )
{
Base* base = CreateRandom();
base->DoIt();
Bar* bar = dynamic_cast<Bar*>(base);
Foo* foo = dynamic_cast<Foo*>(base);
if( bar )
bar->BarIt();
if( foo )
foo->FooIt();
}
return 0;
}
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 eine virtual
Funktion haben. Wenn Ihre Klassen keine polymorphen Typen sind, wird die Verwendung von Basis zu Ableitung von dynamic_cast
nicht kompiliert. Beispiel:
class Base {};
class Der : public Base {};
int main()
{
Base* base = new Der;
Der* der = dynamic_cast<Der*>(base); // ERROR - Won't compile
return 0;
}
Durch Hinzufügen einer virtuellen Funktion zur Basis, z. B. eines virtuellen Dtors, werden sowohl die Basis- als auch die Der-Polymorph-Typen erstellt:
class Base
{
public:
virtual ~Base(){};
};
class Der : public Base {};
int main()
{
Base* base = new Der;
Der* der = dynamic_cast<Der*>(base); // OK
return 0;
}
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".