2009-12-31 18 views
102

Me pregunto cuál es la diferencia entre typeid y typeof en C++. Esto es lo que sé:'typeid' versus 'typeof' en C++

  • typeid se menciona en la documentación para type_info que se define en el archivo de cabecera C++ typeinfo.

  • typeof se define en la extensión GCC para C y en la biblioteca C++ Boost.

Además, aquí es prueba de código de prueba que he creado, donde he descubierto que typeid no devuelve lo que esperaba. ¿Por qué?

main.cpp

#include <iostream> 
#include <typeinfo> //for 'typeid' to work 

class Person { 
    public: 
    // ... Person members ... 
    virtual ~Person() {} 
}; 

class Employee : public Person { 
    // ... Employee members ... 
}; 

int main() { 
    Person person; 
    Employee employee; 
    Person *ptr = &employee; 
    int t = 3; 

    std::cout << typeid(t).name() << std::endl; 
    std::cout << typeid(person).name() << std::endl; // Person (statically known at compile-time) 
    std::cout << typeid(employee).name() << std::endl; // Employee (statically known at compile-time) 
    std::cout << typeid(ptr).name() << std::endl;  // Person * (statically known at compile-time) 
    std::cout << typeid(*ptr).name() << std::endl;  // Employee (looked up dynamically at run-time 
                 // because it is the dereference of a pointer 
                 // to a polymorphic class) 
} 

salida:

bash-3.2$ g++ -Wall main.cpp -o main 
bash-3.2$ ./main 
i 
6Person 
8Employee 
P6Person 
8Employee 
+6

¿De qué manera cree usted que su código no imprime los nombres de los tipos adecuados? Se ve bien para mi. La cadena real devuelta por 'name()' está definida por la implementación. No tiene que ser un nombre de identificador de C++ válido, simplemente * algo * que identifica de manera única el tipo. Parece que su implementación utiliza el esquema general de creación de nombres del compilador. –

+0

Gracias Rob! Esperaba que fueran exactamente los mismos que los nombres de tipo que vi en en.wikipedia.org/wiki/Typeid. ¿Qué puede hacer mangear nombres aquí? – Tim

Respuesta

139

lenguaje C++ no tiene tal cosa como typeof. Debe estar mirando alguna extensión específica del compilador. Si está hablando de typeof de GCC, una característica similar está presente en C++ 11 a través de la palabra clave decltype. Nuevamente, C++ no tiene dicha palabra clave typeof.

typeid es un operador de lenguaje C++ que devuelve información de identificación de tipo en tiempo de ejecución. Básicamente devuelve un objeto type_info, que es comparable a la igualdad con otros objetos type_info.

Note, que la propiedad única definida de la type_info objeto devuelto tiene es su ser igualdad- y no igualdad-comparable, es decir, type_info objetos que describen diferentes tipos deberá comparar no igual, mientras que type_info objetos que describe el mismo tipo tienen que compare igual. Todo lo demás está definido por la implementación. No se garantiza que los métodos que devuelven varios "nombres" devuelvan algo legible para los humanos, e incluso no se garantiza que devuelvan nada.

Tenga en cuenta también, que lo anterior implica probablemente (aunque no parece el estándar mencionar explícitamente) que las aplicaciones consecutivas de typeid al mismo tipo pueden devolver diferentes type_info objetos (que, por supuesto, todavía tiene que comparar la igualdad)

+0

¡Gracias, AndreyT! Acabo de actualizar la publicación con algunas preguntas nuevas. Por favor, eche un vistazo si es posible. – Tim

+0

¿No necesitaría esto una actualización ya que C++ 11 tiene 'decltype'? No estoy seguro de cuál es la política general, pero como la pregunta está etiquetada como 'C++', espero que se refiera al último estándar. Volver a etiquetar la pregunta como 'C++ 03' también sería una opción en sí misma. Personalmente, me confundo bastante a veces, ya que tengo que usar PreC++ 11 en el trabajo y, a veces, no estoy seguro de qué es verdadero "pre11" o "post11". – user463035818

+0

FYI, 'decltype' no es un reemplazo para' typeof'. 'typeof' también funciona en tipos, mientras que' decltype' no. Por ejemplo, 'typeof (int)' es 'int', mientras que' decltype (int) 'es un error. – Shahbaz

34

La principal diferencia entre los dos es la siguiente

  • typeof es un constructo tiempo de compilación y vuelve el tipo como se define en tiempo de compilación
  • typeid es una construcción en tiempo de ejecución y, por lo tanto, proporciona información sobre el tipo de tiempo de ejecución del valor.

typeof Refenence: http://www.delorie.com/gnu/docs/gcc/gcc_36.html

typeid Rfeerence: http://en.wikipedia.org/wiki/Typeid

+0

¡Gracias, JaredPar! Tengo algunas preguntas nuevas en la publicación actualizada después de leer sus respuestas. Por ejemplo, si también es cierto que sus devoluciones se utilizan para diferentes propósitos: el retorno de typeof se usa como tipo de palabra clave que puede definir variable, pero el retorno de typeid no puede? – Tim

23

typeid puede operar en tiempo de ejecución, y devolver un objeto que describe el tipo de tiempo de ejecución del objeto, que debe ser un puntero a un objeto de una clase con métodos virtuales para que RTTI (run-time type information) se almacene en la clase. También puede dar el tipo de tiempo de compilación de una expresión o un nombre de tipo, si no se le da un puntero a una clase con información de tipo de tiempo de ejecución.

typeof es una extensión de GNU y le proporciona el tipo de cualquier expresión en tiempo de compilación. Esto puede ser útil, por ejemplo, para declarar variables temporales en macros que pueden usarse en múltiples tipos. En C++, generalmente usaría templates.

+4

Hasta donde yo sé, 'typeid' aceptará cualquier expresión, no solo aquellas que evalúen objetos con métodos virtuales. Además, 'typeid' aceptará un tipo * nombre *, no solo una expresión. Puede decir 'typeid (5)' o 'typeid (std :: string)' si lo desea. –

+1

He aclarado mi respuesta para dejar eso en claro; 'typeid' * puede * devolver información de tipo tiempo de ejecución si está disponible, pero proporcionará información del tipo de tiempo de compilación para cualquier otra cosa. –

+0

¡Gracias, Brian y Rob!Tengo algunas preguntas nuevas en la publicación actualizada después de leer sus respuestas. – Tim

19

Respondiendo a la pregunta adicional:

mi siguiente código de prueba para typeid hace no emitirá el nombre del tipo correcto. ¿Qué pasa?

No hay nada de malo. Lo que ves es la representación de cadena del nombre de tipo. El C++ estándar no obliga a los compiladores a emitir el nombre exacto de la clase, sino que depende del implementador (proveedor del compilador) decidir qué es lo adecuado. En resumen, los nombres dependen del compilador.


Estas son dos herramientas diferentes.typeof devuelve el tipo de una expresión, pero no es estándar. En C++ 0x hay algo llamado decltype que hace el mismo trabajo AFAIK.

decltype(0xdeedbeef) number = 0; // number is of type int! 
decltype(someArray[0]) element = someArray[0]; 

Mientras typeid se utiliza con los tipos polimórficos. Por ejemplo, supongamos que un cat deriva animal:

animal* a = new cat; // animal has to have at least one virtual function 
... 
if(typeid(*a) == typeid(cat)) 
{ 
    // the object is of type cat! but the pointer is base pointer. 
} 
+0

¡Gracias, Arak! Acabo de actualizar la publicación con algunas preguntas nuevas. Por favor, eche un vistazo si es posible. – Tim

2

Puede utilizar demangle Boost para lograr un buen nombre buscando:

#include <boost/units/detail/utility.hpp> 

y algo así como

To_main_msg_evt ev("Failed to initialize cards in " + boost::units::detail::demangle(typeid(*_IO_card.get()).name()) + ".\n", true, this); 
4

typeid proporciona el tipo de los datos en tiempo de ejecución, cuando se le preguntó por. Typedef es una construcción de tiempo de compilación que define un nuevo tipo como se indica después de eso. No hay ninguna typeof en C++ salida aparece como (mostrado como comentarios inscritas):

std::cout << typeid(t).name() << std::endl; // i 
std::cout << typeid(person).name() << std::endl; // 6Person 
std::cout << typeid(employee).name() << std::endl; // 8Employee 
std::cout << typeid(ptr).name() << std::endl;  // P6Person 
std::cout << typeid(*ptr).name() << std::endl;  //8Employee