Operador typeid

La sintaxis de este operador es:

const type_info typeid(<tipo>)
const type_info typeid(<objeto>)

El tipo puede ser cualquiera de los fundamentales, derivados o una clase, estructura o unión. Si se trata de un objeto, también puede ser de cualquier tipo.

El valor de retorno un objeto constante de tipo type_info.

La clase type_info se define en el fichero de cabecera estándar "typeinfo". Tiene la siguiente declaración:

class type_info {
  public:
    virtual ~type_info();

  private:
    type_info& operator=(const type_info&);
    type_info(const type_info&);
    
  protected:
    const char *__name;
    
  protected:
    explicit type_info(const char *__n): __name(__n) { }
    
  public:
    const char* name() const;
    bool before(const type_info& __arg) const;
    bool operator==(const type_info& __arg) const;
    bool operator!=(const type_info& __arg) const;
    ...
};

Nos interesa, concretamente, la función "name", y tal vez, los operadores == y !=.

La función "name" nos permite mostrar el nombre del tipo a que pertenece un objeto, los operadores nos permiten averiguar si dos objetos son del mismo tipo, o clase o si dos clases o tipos son equivalentes, por ejemplo:

#include <iostream>
#include <typeinfo>
using namespace std;

struct punto3D {
   int x,y,z;
};

union Union {
  int x;
  float z;
  char a;
};

class Clase {
  public:
   Clase() {}
};

typedef int Entero;

int main() {
   int x;
   float y;
   int z[10];
   punto3D punto3d;
   Union uni;
   Clase clase;
   void *pv;
   
   cout << "variable int: " << typeid(x).name() << endl;
   cout << "variable float: " << typeid(y).name() << endl;
   cout << "array de 10 int:" << typeid(z).name() << endl;
   cout << "estructura global: " << typeid(punto3d).name() 
        << endl;
   cout << "unión global: " << typeid(uni).name() << endl;
   cout << "clase global: " << typeid(clase).name() 
        << endl;
   cout << "puntero void: " << typeid(pv).name() << endl;
   cout << "typodef Entero: " << typeid(Entero).name() 
        << endl;
   if(typeid(Entero) == typeid(int)) 
      cout << "int y Entero son el mismo tipo" << endl;
   
   return 0;
}

Ejecutar este código en codepad.

La salida, en Dev-C++, tiene esta forma:

variable int: i
variable float: f
array de 10 int:A10_i
estructura global: 7punto3D
unión global: 5Union
clase global: 5Clase
puntero void: Pv
typodef Entero: i
int y Entero son el mismo tipo

La utilidad es detectar los tipos de objetos durante la ejecución, sobre todo en aplicaciones con frecuente uso de polimorfismo, y que requieran diferentes formas de manejar cada objeto en función de su clase.

Además de usar el operador typeid se puede usar el operador dynamic_cast, que se explica en el siguiente punto.

Comentarios de los usuarios (5)

JCarlos
2013-09-17 10:45:04

Hola.

En la salida del programa donde se usa Typeid:

variable int: i

variable float: f

array de 10 int:A10_i

estructura global: 7punto3D

unión global: 5Union

clase global: 5Clase

puntero void: Pv

typodef Entero: i

int y Entero son el mismo tipo

que significa el 7 de 7punto3D y el 5 de 5Union y 5Clase?

Gracias y un saludo.

Steven R. Davidson
2013-09-17 17:23:01

Hola JCarlos,

Son nombres decorados que dependen de la implementación. Cada compilador y enlazador guarda los nombres de las funciones y en el caso de la RTTI (Información de Tipos en Tiempo de Ejecución) también guarda los nombres de las estructuras (struct, union, y class). Típicamente, guarda estos nombres junto con otra información útil, por lo que sigue algún patrón para "decorar" o "codificar" el nombre completo.

En el caso del ejemplo anterior, el 5 y el 7 parecen indicar la cantidad de caracteres del nombre original: 5 caracteres para "punto3D" y 7 para "Union" y para "Clase". Recuerda que esto no es estándar, por lo que obtendrás diferentes resultados si usas otro compilador o enlazador; o incluso diferentes versiones de estas mismas herramientas.

Espero haber aclarado la duda.

Steven

JCarlos
2013-09-17 19:09:58

Gracias Steven. Duda aclarada, pero si quiero saber de que clase es un objeto, por ejemplo comparando en un condicional con lo que me devuelve name(), primero debo saber que nombre de clase me devuelve name() según el compilador?

#include <iostream>
using namespace std;

class A
{
   public:
     A(int a):datoA(a){}
   private:
     int datoA;
};

int main()
{
    A a(12);

    //Para ver que nombre de clase me devuelve el compilador
    //suponiendo que es "1A":
    cout << typeid(A).name() << endl; 

    if(strcmp(typeid(a).name(),"1A")==0)
       cout << "a es de tipo A" << endl;

    cin.get();
    return 0;
}

O hay otra forma de ver a que clase o tipo pertenece un objeto?

Steven R. Davidson
2013-09-17 20:50:36

Hola JCarlos,

No compararíamos nombres, por los problemas de compatibilidad entre implementaciones, y si no existen tales problemas, tampoco lo haríamos por motivos de optimización: comparar cadenas supone realizar varias comparaciones entre caracteres.

La solución es usar los operadores sobrecargados de 'typeinfo': == y !=. Por ejemplo,

Clase obj;

if( typeid(Clase) == typeid(obj) )
{
  ...
}

Recuerda que este sistema, acerca de tipos de datos, no debería ser la primera solución a un problema de diseño de la implementación de tu proyecto. Es decir, prueba con otras soluciones, que seguramente involucrarán herencia y polimorfismo, y posiblemente punteros a funciones. Si ninguna de estas soluciones te sirve, entonces haz uso de la RTTI.

Espero haber aclarado el tema.

Steven

JCarlos
2013-09-17 20:59:12

Gracias Steven tema aclarado.

Y un saludo.