2009-12-31 12 views
102

Ich frage mich, was der Unterschied zwischen typeid und typeof in C++ ist. Hier ist, was ich weiß:'typeid' versus 'typeof' in C++

  • typeid ist in der Dokumentation für type_info genannt, die in der C++ Header-Datei definiert ist typeinfo.

  • typeof ist in der GCC-Erweiterung für C und in der C++ Boost-Bibliothek definiert.

Auch hier ist Testcode Test, die ich angelegt habe, wo ich entdeckt habe, dass typeid nicht zurück, was ich erwartet hatte. Warum?

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) 
} 

output:

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

In welcher Art und Weise denken Sie Ihren Code druckt nicht die richtigen Namen? Es sieht gut aus für mich. Die tatsächliche von 'name()' zurückgegebene Zeichenfolge ist implementierungsdefiniert. Es muss kein gültiger C++ - Bezeichnername sein, nur * etwas *, das den Typ eindeutig identifiziert. Es sieht so aus, als ob Ihre Implementierung das allgemeine Namens-Mangling-Schema des Compilers verwendet. –

+0

Danke Rob! Ich habe genau die gleichen erwartet wie Typnamen, wie ich es in en.wikipedia.org/wiki/Typeid gesehen habe. Was kann die Namensgebung hier tun? – Tim

Antwort

139

C++ Sprache hat nicht so etwas wie typeof. Sie müssen sich eine bestimmte Compiler-spezifische Erweiterung ansehen. Wenn Sie über GCC typeof sprechen, dann ist ein ähnliches Feature in C++ 11 durch das Schlüsselwort decltype vorhanden. C++ hat wiederum kein Schlüsselwort typeof.

typeid ist ein C++ - Sprachenoperator, der zur Laufzeit Typidentifikationsinformationen zurückgibt. Sie gibt im Wesentlichen ein type_info Objekt zurück, das mit anderen type_info Objekten vergleichbar ist.

Beachten Sie, dass die einzige definierte Eigenschaft des zurück type_info Objekt hat, ist seine gleichstellungs und Nicht-Gleichheit-vergleichbar sein, dh type_info Objekte verschiedene Arten beschreiben soll nicht gleich vergleichen, während type_info Objekte den gleichen Typ beschreiben müssen vergleiche gleich. Alles andere ist implementierungsdefiniert. Methoden, die verschiedene "Namen" zurückgeben, sind nicht garantiert, dass sie irgend etwas, das für Menschen lesbar ist, zurückgeben und sogar nicht garantieren können, irgendetwas zurückzugeben.

Beachten Sie auch, dass die oben impliziert wahrscheinlich (obwohl der Standard scheint nicht explizit zu erwähnen), dass aufeinanderfolgende Anwendungen von typeid auf die gleiche Art können unterschiedliche type_info Objekte zurück (was natürlich immer noch gleich vergleichen müssen).

+0

Vielen Dank, AndreyT! Ich habe gerade den Beitrag mit einigen neuen Fragen aktualisiert. Bitte schauen Sie, wenn möglich. – Tim

+0

würde dies brauchen ein Update seit C++ 11 hat 'declltype'? Ich bin mir nicht sicher, was die allgemeine Richtlinie ist, aber da die Frage mit C++ markiert ist, würde ich erwarten, dass sie sich auf den neuesten Standard bezieht. Die Frage als "C++ 03" zu wiederholen wäre auch eine Option imho. Ich persönlich bin manchmal ziemlich verwirrt, da ich preC++ 11 bei der Arbeit benutzen muss und manchmal bin ich mir nicht sicher, was "pre11" oder "post11" ist. – user463035818

+0

FYI, 'declltype' ist kein Ersatz für' typeof'. 'typeof' funktioniert auch bei Typen, während' decltype' nicht funktioniert. Zum Beispiel ist 'typeof (int)' 'int', während' declltype (int) 'ein Fehler ist. – Shahbaz

34

Der Hauptunterschied zwischen den beiden ist die folgende

  • Typeof ist eine Kompilierung Konstrukts und kehrt der Typ wie unter definiert Kompilierzeit
  • typeid ist ein Laufzeitkonstrukt und gibt somit Auskunft über den Laufzeittyp des Wertes.

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

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

+0

Danke, JaredPar! Ich habe einige neue Fragen im aktualisierten Beitrag nach dem Lesen Ihrer Antworten. Wie wenn es auch wahr ist, dass ihre Rückgaben für verschiedene Zwecke verwendet werden: Die Rückgabe von typeof wird als Typschlüsselwort verwendet, das eine Variable definieren kann, aber die Rückgabe von typeid kann nicht? – Tim

23

typeid zur Laufzeit arbeiten kann, und ein Objekt zurückgeben den Laufzeittyp des Objekts beschreibt, das ein Zeiger auf ein Objekt sein muß eine Klasse mit virtuellen Methoden, um RTTI (run-time type information) in der Klasse zu speichern. Es kann auch den Kompilierzeittyp eines Ausdrucks oder einen Typnamen angeben, wenn ihm kein Zeiger auf eine Klasse mit Informationen zum Laufzeittyp zugewiesen wird.

typeof ist eine GNU-Erweiterung und gibt Ihnen den Typ eines beliebigen Ausdrucks zum Zeitpunkt der Kompilierung. Dies kann beispielsweise nützlich sein, wenn temporäre Variablen in Makros deklariert werden, die für mehrere Typen verwendet werden können. In C++ würden Sie normalerweise stattdessen templates verwenden.

+4

Soweit ich weiß, akzeptiert 'typeid' jeden Ausdruck, nicht nur solche, die Objekte mit virtuellen Methoden auswerten. Darüber hinaus akzeptiert 'typeid' einen Typ * name *, nicht nur einen Ausdruck. Sie können 'typeid (5)' oder 'typeid (std :: string)' sagen, wenn Sie möchten. –

+1

Ich habe meine Antwort geklärt, um das klarzustellen; 'typeid' * kann * Informationen zum Laufzeittyp zurückgeben, wenn sie verfügbar sind, liefert aber Informationen zum Kompilierungszeitpunkt für alles andere. –

+0

Danke, Brian und Rob!Ich habe einige neue Fragen im aktualisierten Beitrag nach dem Lesen Ihrer Antworten. – Tim

19

Beantwortung der Zusatzfrage:

meine folgende Testcode für typeid tut nicht ausgegeben den richtigen Typ Namen. was ist los?

Es ist nichts falsch. Was Sie sehen, ist die Zeichenfolgendarstellung des Typnamens. Das Standard-C++ zwingt Compiler nicht, den exakten Namen der Klasse auszugeben, es liegt nur an dem Implementierer (Compiler-Anbieter), zu entscheiden, was geeignet ist. Kurz gesagt, die Namen hängen vom Compiler ab.


Dies sind zwei verschiedene Werkzeuge.typeof gibt den Typ eines Ausdrucks zurück, ist jedoch kein Standard. In C++ 0x gibt es etwas namens decltype, das den gleichen Job AFAIK tut.

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

Während typeid mit polymorphen Typen verwendet. Zum Beispiel kann sagen, dass cat leitet 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

Danke, Arak! Ich habe gerade den Beitrag mit einigen neuen Fragen aktualisiert. Bitte schauen Sie, wenn möglich. – Tim

2

Sie Boost-demangle verwenden kann, ein gut aussehenden Namen zu erreichen:

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

und so etwas wie

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

typeid bietet die Art der Daten zur Laufzeit, wenn gefragt. Typedef ist ein Kompilierzeit-Konstrukt, das einen neuen Typ definiert, der danach angegeben wird. Es gibt keine typeof in C++ Ausgabe erscheint als (wie beschriftet Kommentare angezeigt):

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