Estou bastante confuso com a dynamic_cast
palavra - chave em 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
}
a definição diz:
A
dynamic_cast
palavra-chave lança um dado de um ponteiro ou tipo de referência para outro, executando uma verificação de tempo de execução para garantir a validade do elenco
Podemos escrever um equivalente de dynamic_cast
C ++ em C para que eu possa entender melhor as coisas?
c++
dynamic-cast
Vijay
fonte
fonte
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'.B* b2 = dynamic_cast<B*> (ap) // 'b'
?b2 is pointer to b
ou o que?Respostas:
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 tipoType*
. 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:dynamic_cast <Tipo *> (ptr)
Isso novamente tenta colocar o ponteiro
ptr
e convertê-lo com segurança em um ponteiro do tipoType*
. 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 derivadoType
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 deptr
fato for derivadoType
, receberá umType*
ponteiro de voltadynamic_cast
. Caso contrário, você receberá um ponteiro NULL.Mas os modelos B2D são um pouco mais complicados. Considere o seguinte código:
main()
não posso dizer que tipo de objetoCreateRandom()
retornará, então o elenco no estilo CBar* bar = (Bar*)base;
não é, com certeza, seguro. Como você pôde consertar isso? Uma maneira seria adicionar uma função como boolAreYouABar() const = 0;
à classe base e retornartrue
deBar
efalse
paraFoo
. Mas há outra maneira: usedynamic_cast<>
: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 umavirtual
função. Se suas classes não são do tipo polimórfico, o uso de base para derivadodynamic_cast
não será compilado. Exemplo:A adição de uma função virtual à base, como um dtor virtual, criará os tipos polimórficos Base e Der:
fonte
Base* base = new Base;
,dynamic_cast<Foo*>(base)
seráNULL
.dynamic_cast<Foo*>(base)
nulo no caso de aBase* base = new Base;
?base
não é umFoo
. UmBase
ponteiro pode apontar para aFoo
, mas ainda é umaFoo
, portanto uma conversão dinâmica funcionará. Se você fazBase* base = new Base
,base
é aBase
, não éFoo
, então você não pode convertê-lo dinamicamente para aFoo
.A menos que você esteja implementando seu próprio RTTI manual (e ignorando o sistema), não é possível implementar
dynamic_cast
diretamente no código em nível de usuário do C ++.dynamic_cast
está muito ligado ao sistema RTTI da implementação C ++.Mas, para ajudá-lo a entender mais o RTTI (e, portanto
dynamic_cast
), você deve ler o<typeinfo>
cabeçalho e otypeid
operador. Isso retorna as informações de tipo correspondentes ao objeto que você tem em mãos e você pode consultar várias coisas (limitadas) desses objetos de informações de tipo.fonte
dynamic_cast
são muito reduzidos. :-P Apenas brinque com você mesmo até pegar o jeito. :-)Mais do que código em C, acho que uma definição em inglês pode ser suficiente:
Dada uma classe Base da qual existe uma classe derivada Derivada,
dynamic_cast
ele converterá um ponteiro Base em um ponteiro Derivado se e somente se o objeto real apontado for de fato um objeto Derivado.No exemplo, a chamada para
test
vincula objetos diferentes a uma referênciaBase
. Internamente, a referência é reduzida para uma referênciaDerived
tipicamente segura: o downcast será bem-sucedido apenas nos casos em que o objeto referenciado for realmente uma instância deDerived
.fonte
O seguinte não é muito parecido com o que você obtém dos C ++
dynamic_cast
em termos de verificação de tipo, mas talvez isso o ajude a entender um pouco melhor sua finalidade:fonte
A
dynamic_cast
executa uma verificação de tipo usando RTTI . Se falhar, gerará uma exceção (se você tiver dado uma referência) ou NULL se você tiver dado um ponteiro.fonte
Primeiro, para descrever a conversão dinâmica em termos C, temos que representar classes em C. Classes com funções virtuais usam um "VTABLE" de ponteiros para as funções virtuais. Comentários são C ++. Sinta-se à vontade para reformatar e corrigir erros de compilação ...
Então, um elenco dinâmico é algo como:
fonte
Não há aulas em C, por isso é impossível escrever dynamic_cast nesse idioma. As estruturas C não têm métodos (como resultado, eles não têm métodos virtuais); portanto, não há nada "dinâmico" nela.
fonte
Não, não é fácil. O compilador atribui uma identidade exclusiva a todas as classes, essas informações são referenciadas por todas as instâncias de objetos e é isso que é inspecionado no tempo de execução para determinar se uma conversão dinâmica é legal. Você pode criar uma classe base padrão com essas informações e operadores para fazer a inspeção em tempo de execução nessa classe base; qualquer classe derivada informará a classe base sobre seu lugar na hierarquia de classes e quaisquer instâncias dessas classes poderão ser executadas em tempo de execução via suas operações.
editar
Aqui está uma implementação que demonstra uma técnica. Não estou afirmando que o compilador usa algo assim, mas acho que demonstra os conceitos:
fonte
dynamic_cast usa RTTI. Ele pode desacelerar seu aplicativo, você pode usar a modificação do padrão de design do visitante para obter downcasting sem RTTI http://arturx64.github.io/programming-world/2016/02/06/lazy-visitor.html
fonte
static_cast< Type* >(ptr)
static_cast em C ++ pode ser usado em cenários em que todos os tipos de conversão podem ser verificados em tempo de compilação .
dynamic_cast< Type* >(ptr)
dynamic_cast em C ++ pode ser usado para executar conversão de tipo segura para baixo . dynamic_cast é um polimorfismo em tempo de execução. O operador dynamic_cast, que converte com segurança de um ponteiro (ou referência) em um tipo base em um ponteiro (ou referência) em um tipo derivado.
por exemplo 1:
Para mais informações clique aqui
por exemplo 2:
fonte