[C con Clase] typeid

Steven Davidson steven en conclase.net
Dom Abr 8 07:23:32 CEST 2007


Hola Reinel,

El pasado 2007-04-07 18:54:05, Rey escribió:

R> Buenas a todos los compañeros de la lista.
R>  
R> Oigan, podrían argumentarme un poco sobre el asunto, es decir, el typeid. Utilidad, etc.
R>  

Se trata de un operador de C++ que junto a la clase 'type_info', definida en <typeinfo>, tienen que ver con la RTTI: Información del Tipo en Tiempo de Ejecución. Por lo general y por defecto, la RTTI no se aplica implícitamente al compilar y enlazar un programa de C++. Sencillamente, la RTTI agrega mucho más código y suele provocar una ralentización agregada a la ejecución del programa.

Con la RTTI, podemos determinar ciertos aspectos de los tipos dentro de nuestro programa cuando típicamente no los conocemos. La clase 'type_info' se define como:

class type_info
{
public:
  virtual ~type_info();

  int operator==( const type_info & ) const;  // para comparar
  int operator!=( const type_info & ) const;
  int before( const type_info & ) const;      // determinar el orden

  const char *name() const;                   // nombre del tipo

private:
  type_info( const type_info & );             // prevenir copiar
  type_info &operator=( const type_info & );  // prevenir copiar
  ...
};

El operador tiene dos versiones:

typeid( <nombre_del_tipo> )
typeid( <expresión> )

En ambos casos, se retorna una referencia a un objeto constante de 'type_info'; o sea, obtenemos un 'const type_info &'.

Por ejemplo,

void func( Base *ptr )
{
  if( typeid( *ptr ) == typeid( Der3 ) )  // ¿ Es 'ptr' de tipo 'Der3 *' ?
  ...
}

Debo aclarar y recalcar que se puede abusar muy fácilmente de la RTTI, cuando en la gran mayoría de los casos no es necesario usarla. Por ejemplo,

void dibujar( const Figura *ptr )
{
  if( typeid(*ptr) == typeid(Circulo) )
  { ... }
  else if( typeid(*ptr) == typeid(Rectangulo) )
  { ... }
  else if( typeid(*ptr) == typeid(Cuadrado) )
  { ... }
  else if( typeid(*ptr) == typeid(Triangulo) )
  { ... }
  else if( typeid(*ptr) == typeid(Rombo) )
  { ... }
}

Esto es un caso de "abuso" de la RTTI, ya que con polimorfismo, funciones virtuales, y un buen diseño, nos libramos de usarla. Esto sería,

void dibujar( const Figura *ptr )
{
  ptr->dibujar();
}

Si tenemos que hacer algo específico según la clase original, entonces usamos el operador 'dynamic_cast'. Por ejemplo,

void dibujar( const Figura *ptr )
{
  if( dynamic_cast< const Circulo * >( ptr ) )
  { ... }
  else if( dynamic_cast< const Rectangulo * >( ptr  )
  { ... }
  else if( dynamic_cast< const Cuadrado * >( ptr ) )
  { ... }
  else if( dynamic_cast< const Triangulo * >( ptr ) )
  { ... }
  else if( dynamic_cast< const Rombo * >( ptr ) )
  { ... }
}

Esto es parecido al código anterior con 'typeid()', pero no usamos la RTTI.


Mi consejo es que no tientes usar la RTTI al menos que lo hayas pensado MUY MUY bien y no veas otra solución. Por lo general, se usa la RTTI para crear programas a modo de herramientas o incluso bibliotecas auxiliares que son tan genéricas que al final necesitan información del tipo a manejar.


Espero haber aclarado un poco este tema.

Steven


Más información sobre la lista de distribución Cconclase