Aqui está um resumo static_cast<>
e, dynamic_cast<>
especificamente, no que diz respeito aos ponteiros. Este é apenas um resumo de nível 101, que não cobre todos os meandros.
static_cast <Tipo *> (ptr)
Isso pega o ponteiro ptr
e tenta convertê-lo com segurança em um ponteiro do tipo Type*
. Este elenco é feito em tempo de compilação. Ele só executará a conversão se os tipos de tipo estiverem relacionados. Se os tipos não estiverem relacionados, você receberá um erro do compilador. Por exemplo:
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 <Tipo *> (ptr)
Isso novamente tenta colocar o ponteiro ptr
e convertê-lo com segurança em um ponteiro do tipo Type*
. Mas esse elenco é executado em tempo de execução, não em tempo de compilação. Por ser uma conversão em tempo de execução, é útil principalmente quando combinada com classes polimórficas. De fato, em casos certianos, as classes devem ser polimórficas para que o elenco seja legal.
As transmissões podem seguir uma de duas direções: da base para a derivada (B2D) ou da derivada para a base (D2B). É simples o suficiente para ver como o D2B lança funcionaria em tempo de execução. Ou ptr
foi derivado Type
ou não era. No caso do D2B dynamic_cast <> s, as regras são simples. Você pode tentar converter qualquer coisa para qualquer outra coisa e, se de ptr
fato for derivado Type
, receberá um Type*
ponteiro de volta dynamic_cast
. Caso contrário, você receberá um ponteiro NULL.
Mas os modelos B2D são um pouco mais complicados. Considere o seguinte código:
#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()
não posso dizer que tipo de objeto CreateRandom()
retornará, então o elenco no estilo C Bar* bar = (Bar*)base;
não é, com certeza, seguro. Como você pôde consertar isso? Uma maneira seria adicionar uma função como bool AreYouABar() const = 0;
à classe base e retornar true
de Bar
e false
para Foo
. Mas há outra maneira: use 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;
}
Os lançamentos são executados em tempo de execução e funcionam consultando o objeto (não há necessidade de se preocupar com o por enquanto), perguntando se é do tipo que estamos procurando. Se for, dynamic_cast<Type*>
retorna um ponteiro; caso contrário, ele retornará NULL.
Para que essa conversão de base para derivada funcione dynamic_cast<>
, Base, Foo e Bar devem ser o que o Padrão chama de tipos polimórficos . Para ser do tipo polimórfico, sua classe deve ter pelo menos uma virtual
função. Se suas classes não são do tipo polimórfico, o uso de base para derivado dynamic_cast
não será compilado. Exemplo:
class Base {};
class Der : public Base {};
int main()
{
Base* base = new Der;
Der* der = dynamic_cast<Der*>(base); // ERROR - Won't compile
return 0;
}
A adição de uma função virtual à base, como um dtor virtual, criará os tipos polimórficos Base e Der:
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<>
funciona nos bastidores (ou quanto do C ++ funciona), um bom livro (que também é bastante fácil de ler para algo tão técnico) é o "Inside the C ++ Object Model" de Lippman. Também os livros "Design and Evolution of C ++" e "The C ++ Programming Language" de Stroustrup são bons recursos, mas o livro de Lippman é dedicado a como o C ++ funciona 'nos bastidores'.