Estoy bastante confundido con la dynamic_cast
palabra clave en 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
}
la definición dice:
La
dynamic_cast
palabra clave arroja un dato de un puntero o tipo de referencia a otro, realizando una verificación de tiempo de ejecución para garantizar la validez del molde.
¿Podemos escribir un equivalente de dynamic_cast
C ++ en C para poder entender mejor las cosas?
c++
dynamic-cast
Vijay
fuente
fuente
dynamic_cast<>
funciona detrás de escena (o cuánto funciona C ++), un buen libro (que también es bastante fácil de leer para algo tan técnico) es "Inside the C ++ Object Model" de Lippman. También los libros "Diseño y evolución de C ++" y "El lenguaje de programación C ++" de Stroustrup son buenos recursos, pero el libro de Lippman está dedicado a cómo funciona C ++ "detrás de escena".B* b2 = dynamic_cast<B*> (ap) // 'b'
?b2 is pointer to b
¿o que?Respuestas:
Aquí hay un resumen
static_cast<>
ydynamic_cast<>
específicamente en lo que respecta a los punteros. Este es solo un resumen de 101 niveles, no cubre todas las complejidades.static_cast <Tipo *> (ptr)
Esto toma el puntero
ptr
e intenta convertirlo de manera segura en un puntero de tipoType*
. Este reparto se realiza en tiempo de compilación. Solo realizará la conversión si los tipos de tipos están relacionados. Si los tipos no están relacionados, obtendrá un error de compilación. Por ejemplo:Dynamic_cast <Tipo *> (ptr)
Esto intenta nuevamente tomar el puntero
ptr
y convertirlo de manera segura en un puntero de tipoType*
. Pero este reparto se ejecuta en tiempo de ejecución, no en tiempo de compilación. Debido a que este es un lanzamiento en tiempo de ejecución, es útil especialmente cuando se combina con clases polimórficas. De hecho, en casos certian las clases deben ser polimórficas para que el reparto sea legal.Los moldes pueden ir en una de dos direcciones: de base a derivada (B2D) o de derivada a base (D2B). Es lo suficientemente simple como para ver cómo los moldes D2B funcionarían en tiempo de ejecución. O
ptr
se derivaba deType
o no. En el caso de D2B dynamic_cast <> s, las reglas son simples. Puede intentar lanzar cualquier cosa a otra cosa, y siptr
de hecho se derivóType
, obtendrá unType*
puntero de regresodynamic_cast
. De lo contrario, obtendrá un puntero NULL.Pero los modelos B2D son un poco más complicados. Considere el siguiente código:
main()
no puedo decir qué tipo de objetoCreateRandom()
volverá, por lo que el reparto de estilo CBar* bar = (Bar*)base;
definitivamente no es seguro para escribir. ¿Cómo puedes arreglar esto? Una forma sería agregar una función como boolAreYouABar() const = 0;
a la clase base y regresartrue
desdeBar
yfalse
desdeFoo
. Pero hay otra forma: usedynamic_cast<>
:Los lanzamientos se ejecutan en tiempo de ejecución y funcionan consultando el objeto (no hay que preocuparse por cómo hacerlo por ahora), preguntándole si es del tipo que estamos buscando. Si es así,
dynamic_cast<Type*>
devuelve un puntero; de lo contrario, devuelve NULL.Para que esta conversión de base a derivada funcione
dynamic_cast<>
, Base, Foo y Bar deben ser lo que el Estándar llama tipos polimórficos . Para ser un tipo polimórfico, su clase debe tener al menos unavirtual
función. Si sus clases no son tipos polimórficos, el uso de base a derivada dedynamic_cast
no se compilará. Ejemplo:Agregar una función virtual a la base, como un dtor virtual, hará que los tipos polimórficos Base y Der:
fuente
Base* base = new Base;
,dynamic_cast<Foo*>(base)
lo seráNULL
.dynamic_cast<Foo*>(base)
es nulo en caso de aBase* base = new Base;
?base
no es unFoo
. UnBase
puntero puede apuntar a unFoo
, pero sigue siendo unFoo
, por lo que un reparto dinámico funcionará. Si lo haceBase* base = new Base
,base
es aBase
, no aFoo
, por lo que no puede convertirlo dinámicamente en aFoo
.A menos que esté implementando su propio RTTI enrollado a mano (y evitando el sistema), no es posible implementarlo
dynamic_cast
directamente en el código de nivel de usuario C ++.dynamic_cast
está muy vinculado al sistema RTTI de la implementación de C ++.Pero, para ayudarlo a comprender RTTI (y por lo tanto
dynamic_cast
) más, debe leer el<typeinfo>
encabezado y eltypeid
operador. Esto devuelve la información de tipo correspondiente al objeto que tiene a mano, y puede consultar varias cosas (limitadas) de estos objetos de información de tipo.fuente
dynamic_cast
son muy escasos. :-P Solo juega con él hasta que te acostumbres. :-)Más que el código en C, creo que una definición en inglés podría ser suficiente:
Dada una clase Base de la cual hay una clase derivada Derivada,
dynamic_cast
convertirá un puntero Base en un puntero Derivado si y solo si el objeto real al que apunta es de hecho un objeto Derivado.En el ejemplo, la llamada a
test
enlaza diferentes objetos a una referenciaBase
. Internamente, la referencia se descarta a una referencia deDerived
una forma segura: el downcast tendrá éxito solo para aquellos casos en los que el objeto referenciado sea realmente una instancia deDerived
.fuente
Lo siguiente no está realmente cerca de lo que obtienes de C ++
dynamic_cast
en términos de verificación de tipo, pero tal vez te ayudará a comprender un poco mejor su propósito:fuente
A
dynamic_cast
realiza una verificación de tipo usando RTTI . Si falla, le arrojará una excepción (si le dio una referencia) o NULL si le dio un puntero.fuente
Primero, para describir la conversión dinámica en términos de C, tenemos que representar las clases en C. Las clases con funciones virtuales usan un "VTABLE" de punteros a las funciones virtuales. Los comentarios son C ++. Siéntase libre de formatear y corregir errores de compilación ...
Entonces un elenco dinámico es algo así como:
fuente
No hay clases en C, por lo que es imposible escribir dynamic_cast en ese lenguaje. Las estructuras C no tienen métodos (como resultado, no tienen métodos virtuales), por lo que no hay nada "dinámico" en ellas.
fuente
No, no fácilmente. El compilador asigna una identidad única a cada clase, esa información es referenciada por cada instancia de objeto, y eso es lo que se inspecciona en tiempo de ejecución para determinar si una conversión dinámica es legal. Puede crear una clase base estándar con esta información y operadores para hacer la inspección de tiempo de ejecución en esa clase base, luego cualquier clase derivada informaría a la clase base de su lugar en la jerarquía de clases y cualquier instancia de esas clases sería ejecutable en tiempo de ejecución a través de sus operaciones
editar
Aquí hay una implementación que demuestra una técnica. No estoy afirmando que el compilador use algo como esto, pero creo que demuestra los conceptos:
fuente
Dynamic_cast utiliza RTTI. Puede ralentizar su aplicación, puede utilizar la modificación del patrón de diseño del visitante para lograr la conversión sin RTTI http://arturx64.github.io/programming-world/2016/02/06/lazy-visitor.html
fuente
static_cast< Type* >(ptr)
static_cast en C ++ se puede usar en escenarios donde se puede verificar todo tipo de conversión en tiempo de compilación .
dynamic_cast< Type* >(ptr)
Dynamic_cast en C ++ se puede utilizar para realizar el tipo de conversión segura . dynamic_cast es un polimorfismo en tiempo de ejecución. El operador dynamic_cast, que convierte de forma segura un puntero (o referencia) a un tipo base en un puntero (o referencia) a un tipo derivado.
por ejemplo 1:
Para más información haga clic aquí.
por ejemplo 2:
fuente