typeid Operator
Fragt Informationen über einen Typ ab.
Wird verwendet, wenn der dynamische Typ eines polymorphen Objekts bekannt sein muss, und für die statische Typidentifizierung.
Inhalt |
[bearbeiten] Syntax
typeid ( Typ ) |
(1) | ||||||||
typeid ( Ausdruck ) |
(2) | ||||||||
Der typeid-Ausdruck ist ein lvalue-Ausdruck, der auf ein Objekt mit statischer Speicherklasse verweist, und zwar auf die const-qualifizierte Version des polymorphen Typs std::type_info oder einen davon abgeleiteten Typ.
Wenn die Standardbibliotheksdefinition von std::type_info bei der Verwendung von typeid nicht sichtbar ist, ist das Programm schlecht geformt.
[bearbeiten] Erklärung
Wenn Typ oder der Typ von Ausdruck ein Klassentyp oder eine Referenz auf einen Klassentyp ist, dann darf dieser Klassentyp kein unvollständiger Typ sein.
- Wenn Ausdruck ein lvalue(bis C++11)glvalue(seit C++11) Ausdruck ist, der ein Objekt eines polymorphen Typs identifiziert (d. h. eine Klasse, die mindestens eine virtuelle Funktion deklariert oder erbt), wertet der typeid-Ausdruck den Ausdruck aus und verweist dann auf das std::type_info-Objekt, das den dynamischen Typ des Ausdrucks repräsentiert.
- Wenn Ausdruck ein Dereferenzierungsausdruck ist und sein Operand zu einem Nullzeigerwert ausgewertet wird, wird eine Ausnahme vom Typ std::bad_typeid ausgelöst[1].
- Andernfalls wertet typeid den Ausdruck nicht aus, und das von std::type_info identifizierte Objekt repräsentiert den statischen Typ des Ausdrucks. Lvalue-zu-rvalue-, Array-zu-Zeiger- oder Funktions-zu-Zeiger-Konvertierungen werden nicht durchgeführt.
|
(seit C++17) |
Wenn Typ oder der Typ von Ausdruck cv-qualifiziert ist, verweist das Ergebnis von typeid auf ein std::type_info-Objekt, das den cv-unqualifizierten Typ repräsentiert (d. h. typeid(const T) == typeid(T)).
Wenn typeid auf ein Objekt während des Konstruktions- oder Zerstörungsprozesses angewendet wird (in einem Destruktor oder in einem Konstruktor, einschließlich der Initialisierungsliste oder Standard-Member-Initialisierer), dann repräsentiert das von diesem typeid referenzierte std::type_info-Objekt die Klasse, die gerade konstruiert oder zerstört wird, auch wenn es nicht die am weitesten abgeleitete Klasse ist.
- ↑ In anderen Kontexten führt die Auswertung eines solchen Ausdrucks zu undefiniertem Verhalten.
[bearbeiten] Anmerkungen
Wenn typeid auf einen Ausdruck vom polymorphen Typ angewendet wird, kann die Auswertung von typeid Laufzeitaufwand verursachen (ein virtueller Tabellen-Lookup); andernfalls wird der typeid-Ausdruck zur Kompilierzeit aufgelöst.
Es ist nicht spezifiziert, ob der Destruktor für das Objekt, auf das von typeid verwiesen wird, am Ende des Programms aufgerufen wird.
Es gibt keine Garantie, dass auf dasselbe std::type_info-Objekt von allen Auswertungen des typeid-Ausdrucks auf denselben Typ verwiesen wird, obwohl sie gleich verglichen würden, std::type_info::hash_code dieser type_info-Objekte identisch wäre, ebenso wie ihr std::type_index.
const std::type_info& ti1 = typeid(A); const std::type_info& ti2 = typeid(A); assert(&ti1 == &ti2); // not guaranteed assert(ti1 == ti2); // guaranteed assert(ti1.hash_code() == ti2.hash_code()); // guaranteed assert(std::type_index(ti1) == std::type_index(ti2)); // guaranteed
[bearbeiten] Schlüsselwörter
[bearbeiten] Beispiel
Das Beispiel zeigt die Ausgabe einer der Implementierungen, bei der type_info::name vollständige Typnamen zurückgibt; filtern Sie mit c++filt -t, wenn Sie gcc oder ähnliches verwenden.
#include <iostream> #include <string> #include <typeinfo> struct Base {}; // non-polymorphic struct Derived : Base {}; struct Base2 { virtual void foo() {} }; // polymorphic struct Derived2 : Base2 {}; int main() { int myint = 50; std::string mystr = "string"; double *mydoubleptr = nullptr; std::cout << "myint has type: " << typeid(myint).name() << '\n' << "mystr has type: " << typeid(mystr).name() << '\n' << "mydoubleptr has type: " << typeid(mydoubleptr).name() << '\n'; // std::cout << myint is a glvalue expression of polymorphic type; it is evaluated const std::type_info& r1 = typeid(std::cout << myint); // side-effect: prints 50 std::cout << '\n' << "std::cout<<myint has type : " << r1.name() << '\n'; // std::printf() is not a glvalue expression of polymorphic type; NOT evaluated const std::type_info& r2 = typeid(std::printf("%d\n", myint)); std::cout << "printf(\"%d\\n\",myint) has type : " << r2.name() << '\n'; // Non-polymorphic lvalue is a static type Derived d1; Base& b1 = d1; std::cout << "reference to non-polymorphic base: " << typeid(b1).name() << '\n'; Derived2 d2; Base2& b2 = d2; std::cout << "reference to polymorphic base: " << typeid(b2).name() << '\n'; try { // dereferencing a null pointer: okay for a non-polymorphic expression std::cout << "mydoubleptr points to " << typeid(*mydoubleptr).name() << '\n'; // dereferencing a null pointer: not okay for a polymorphic lvalue Derived2* bad_ptr = nullptr; std::cout << "bad_ptr points to... "; std::cout << typeid(*bad_ptr).name() << '\n'; } catch (const std::bad_typeid& e) { std::cout << " caught " << e.what() << '\n'; } }
Mögliche Ausgabe
======== output from Clang ========
myint has type: i
mystr has type: NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
mydoubleptr has type: Pd
50
std::cout<<myint has type : NSt3__113basic_ostreamIcNS_11char_traitsIcEEEE
printf("%d\n",myint) has type : i
reference to non-polymorphic base: 4Base
reference to polymorphic base: 8Derived2
mydoubleptr points to d
bad_ptr points to... caught std::bad_typeid
======== output from MSVC ========
myint has type: int
mystr has type: class std::basic_string<char,struct std::char_traits<char>,⮠
class std::allocator<char> >
mydoubleptr has type: double * __ptr64
50
std::cout<<myint has type : class std::basic_ostream<char,struct std::char_traits<char> >
printf("%d\n",myint) has type : int
reference to non-polymorphic base: struct Base
reference to polymorphic base: struct Derived2
mydoubleptr points to double
bad_ptr points to... caught Attempted a typeid of nullptr pointer![bearbeiten] Fehlerberichte
Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| CWG 492 | C++98 | wenn typeid auf eine Referenz auf einen cv-qualifizierten Typ angewendet wird repräsentierte das Ergebnis den referenzierten Typ |
das Ergebnis repräsentiert den cv-unqualifizierten referenzierten Typ |
| CWG 1416 | C++98 | die Formulierung bezüglich der obersten cv-Qualifikation könnte fehlinterpretiert werden |
verbesserte die Formulierung |
| CWG 1431 | C++98 | typeid durfte nur std::bad_typeid auslösen | durfte auslösen abgleichbare abgeleitete Klassen |
| CWG 1954 | C++98 | es war unklar, ob eine Dereferenzierung eines Nullzeigers in Subausdrücken von Ausdruck überprüft werden kann |
nur auf oberster Ebene überprüft |
[bearbeiten] Siehe auch
| enthält Informationen über bestimmte Typen, die Klasse, die vom typeid-Operator zurückgegeben wird (Klasse) |