====== Der typeid-Operator ====== Mit Hilfe des typeid-Operators erhält man von C++ eine Referenz auf eine [[cpp:std:type_info|std::type_info]]-Struktur. Es kann sein, dass RTTI je nach Compiler noch mit einem Compilerflag aktiviert werden muss. Um die [[cpp:std:type_info|std::type_info]]-Struktur nutzen zu können, muss der C++-Header ''typeinfo'' includiert werden. #include ===== Typen vergleichen ===== Die [[cpp:std:type_info]]-Struktur ist für alle Objekte eines Typs identisch, wie es auch die vTable ist. Somit kann man Typen von Variablen miteinander oder mit expliziten Typen vergleichen: ==== statisch Typen vergleichen (ohne vTable) ==== #include #include #include class Farbe // Farbe hat keine virtuellen Member { public: int rgbWert; }; class FarbeMitAlphaWert : public Farbe { public: int Alpha; }; void test( Farbe & lhs, Farbe & rhs ) { if( typeid( lhs ) == typeid( rhs ) ) printf( "lhs hat den gleichen Typ wie rhs\n" ); else printf( "lhs hat einen anderen Typ als rhs\n" ); } int main( void ) { Farbe farbe1; Farbe farbe2; Farbe const farbeConst = farbe2; if( typeid( farbe1 ) == typeid( farbe2 ) ) printf( "farbe1 hat den gleichen Typ wie Farbe2\n" ); if( typeid( farbe1 ) == typeid( farbeConst ) ) printf( "farbe1 hat den gleichen Typ wie FarbeConst\n" ); if( typeid( farbe1 ) == typeid( int ) ) printf( "farbe1 ist ein int\n" ); if( typeid( farbe1 ) == typeid( int ) ) printf( "farbe1 ist ein int\n" ); else printf( "farbe1 ist KEIN int\n" ); // Ab hier wird es ernst printf( "--------------\n" ); printf( "Groeße einer Farbe: %d\n", sizeof( Farbe )); FarbeMitAlphaWert alpha; printf( "test( farbe1, farbe2 ): " ); test( farbe1, farbe2 ); printf( "test( farbe1, alpha ): " ); test( farbe1, alpha ); return EXIT_SUCCESS; } Das oben stehende Programm kann nur statisch zur Laufzeit prüfen. Hier das Ergebnis: Neo:rtti xin$ ./a.out farbe1 hat den gleichen Typ wie Farbe2 farbe1 hat den gleichen Typ wie FarbeConst farbe1 ist KEIN int -------------- Groeße einer Farbe: 4 test( farbe1, farbe2 ): lhs hat den gleichen Typ wie rhs test( farbe1, alpha ): lhs hat den gleichen Typ wie rhs Während die oberen Tests wunderbar funktionieren, testet die Funktion ''test'' ebenfalls statisch auf den Typ Farbe. Und da Farbe keine virtuellen Methoden kennt, besitzt es keine Objekttyp abhängige RTTI-Information. Eine Farbe mit AlphaWert ist also im Kontext der Funktion ''test'' auch nur eine ''Farbe''. Es kann Compiler geben, bei denen der Text "farbe1 hat den gleichen Typ wie FarbeConst" nicht erscheint, da sie die Attribute const und volatile als eigene Typen darstellen. Vom Standard her sollte nur der Typ unabhängig von den Attributen verglichen werden. ==== statisch Typen vergleichen (ohne vTable) ===== Sobald eine vTable vorhanden ist, unterscheidet sich diese bei jedem Objekttypen. Hierfür geben wir der Klasse Farbe einfach einen überschreibbaren Destruktor mit: class Farbe // Farbe hat nun einen virtuellen Destruktor { public: int rgbWert; virtual ~Farbe() {} }; Entsprechend ändert sich die Ausgabe unseres Testprogramms: farbe1 hat den gleichen Typ wie Farbe2 farbe1 hat den gleichen Typ wie FarbeConst farbe1 ist KEIN int -------------- Groeße einer Farbe: 8 test( farbe1, farbe2 ): lhs hat den gleichen Typ wie rhs test( farbe1, alpha ): lhs hat einen anderen Typ als rhs Die Farbe ist um einige Bytes gewachsen: dies ist der Zeiger auf die vTable. Durch die Tatsache, dass jedes Objekt nun einen Zeiger auf die eigene Objektbeschreibung mit sich führt, können die Objekttypen nun korrekt verglichen werden. Eine ''Farbe'' unterscheidet sich nun von einer ''FarbeMitAlphaWert''. ===== Den Namen eines Typs ausgeben ===== Gerade bei der Fehlersuche ist es manchmal sehr hilfreich zu erfahren, welcher Datentyp soeben in der Funktion verwendet wird. Folgendes kleines Testprogramm holt sich den Namen der Klasse aus der [[cpp:std:type_info|std::type_info]]-Struktur und gibt ihn aus. #include #include #include class Farbe { public: int rgbWert; virtual ~Farbe() {} }; class FarbeMitAlphaWert : public Farbe { public: int Alpha; }; void printName( Farbe & type ) { printf( "%s\n", typeid( type ).name() ); } int main( void ) { Farbe farbe; FarbeMitAlphaWert alpha; printf( "farbe : " ); printName( farbe ); printf( "alpha : " ); printName( alpha ); return EXIT_SUCCESS; } Wie der hier verwendete GCC-Compiler zeigt, muss der Klassenname nicht zwangsläufig identisch mit dem Klassennamen im Quelltext sein: farbe : 5Farbe alpha : 17FarbeMitAlphaWert