Run-Time Type Identification. The typeid operator. Examples
Contents
- 1. The concept of Run-Time Type Identification
- 2. Type identification. The typeid operator
- 3. An example of using the typeid operator for template classes
- Related topics
Search other resources:
1. The concept of Run-Time Type Identification
To support dynamic polymorphism, C++ introduced Run-Time Type Identification (RTTI). This dynamic identification allows the type of an object to be identified when a program is executed. The primary means of dynamic type identification is the typeid operator.
In order to provide better type casting, the latest versions of C++ include additional type casting operators. These operators include:
- dynamic_cast;
- const_cast;
- reinterpret_cast;
- static_cast.
Also, the C++ language has a standard type cast operator, which has the form
(type)expression
More information about this cast operator can be found here.
⇑
2. Type identification. The typeid operator
The C++ programming language supports dynamic polymorphism through a combination of inheritance, virtual functions, and the use of a pointer to the base class. In a class hierarchy, a base class pointer can point to an instance of any class in the hierarchy. Therefore, it is not always possible to guess which class object of the hierarchy the pointer points to. Type identification must be done during the execution of the program.
The typeid operator is used to identify a type in C++. This operator has two forms of use:
- typeid(object) – defining the characteristics of the type of an object or a variable named object;
- typeid(type) – defining characteristics of a type named type.
The typeid() operator returns a reference to an object of type type_info. The type_info class describes the type of an object and has the following internal members:
- Operator functions
bool operator==(const type_info& obj); bool operator!=(const type_info& obj);
These functions overload the == and != comparison operators.
- Function
const char* name();
This function returns a pointer to the name of the type being defined.
- Function
bool before(const type_info& obj);
This function returns true if the calling object precedes the object given as the parameter.
To use the typeid() operator, you need to include the typeinfo module.
#include <typeinfo>
⇑
2.1. The typeid operator for an object
2.1.1. An example of using the typeid operator for base type variables and class objects
#include <iostream> #include <typeinfo> using namespace std; // Some class class MyClass { // ... }; void main() { // Get characteristics of a type based on an object (instance) // 1. Declare variables (objects) of different types int a, b; double x; string s; MyClass obj; // 2. Use a reference to type_info to get information about a type // 2.1. Method name() - get the type name const type_info& ti = typeid(x); cout << "Type of x is: " << ti.name() << endl; // 2.2. Compare object types s and obj const type_info& ti_s = typeid(s); const type_info& ti_obj = typeid(obj); if (ti_s == ti_obj) cout << "typeid(s)==typeid(obj)" << endl; else cout << "typeid(s)!=typeid(obj)" << endl; // 3. Direct use of typeid() without declaring a reference // 3.1. Compare object types a, b - use operator==() function if (typeid(a) == typeid(b)) cout << "Types of a and b are equal." << endl; else cout << "Types of a and b are not equal." << endl; // 3.2. Compare the types of variables x and a use the operator!=() function if (typeid(x) != typeid(a)) cout << "Types of x and a are not equal." << endl; else cout << "Types of x and a are equal." << endl; // 3.3. Get data based on type string tName = typeid(s).name(); cout << "typeid(string) = " << tName << endl; }
Program result
Type of x is: double typeid(s)!=typeid(obj) Types of a and b are equal. Types of x and a are not equal. typeid(string) = class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
⇑
2.1.2. An example of using the typeid operator for objects of classes that form a hierarchy
The typeid operator is useful when classes form a hierarchy and virtual functions are implemented in the classes. The following example declares a base class, Area, and two derived classes, Circle and Rectangle. All 3 classes contain an implementation of the GetArea() virtual function, which returns different area values depending on the selected shape.
For demonstration purposes, the function Demo_ref_typeid() is implemented, which receives a reference to the base class Area. The function calls the typeid operator, which determines the type of the instance passed to the function. The instance type depends on which instance in the class hierarchy was passed when calling the Demo_ref_typeid() function.
The main() function demonstrates using the typeid() operator for class objects and passing it to the Demo_ref_typeid() function.
#include <iostream> #include <typeinfo> using namespace std; // Applying typeid to the class hierarchy // polymorphic class Area class Area { public: virtual double GetArea() { return 0; }; // virtual function }; class Circle :public Area { double r; public: Circle(double _r) { if (_r > 0) r = _r; else r = 1; } double GetArea() { const double pi = 3.1415; return pi * r * r; } }; // Rectangle class Rectangle :public Area { double a, b; public: Rectangle(double _a, double _b) { if ((_a >= 0) && (_b >= 0)) { a = _a; b = _b; } else { a = b = 0.0; } } double GetArea() { return a * b; } }; // Passing a reference to the base class to the method, // if the class is polymorphic, then the type of the reference // is determined by the type of the parameter-object void Demo_ref_typeid(Area& ref) { cout << "The type of ref is: "; cout << typeid(ref).name() << endl; } void main(void) { Area* p; // pointer to the base class Area a; Circle c(3); Rectangle r(7, 5); // this is not possible, the uninitialized value of p // cout << typeid(*p).name() << endl; p = &a; cout << "Pointer p points to object of type: "; cout << typeid(*p).name() << endl; // class Area p = &c; cout << "Pointer p points to object of type: "; cout << typeid(*p).name() << endl; // class Circle p = &r; cout << "Pointer p points to object of type: "; cout << typeid(*p).name() << endl; // class Rectangle // Important: if you remove the word virtual in the Area class, // it will display the following result: // Pointer p points to object of type: class Area // Pointer p points to object of type: class Area // Pointer p points to object of type: class Area // Demonstration of using typeid for references Demo_ref_typeid(a); // The type of ref is: class Area Demo_ref_typeid(c); // The type of ref is: class Circle Demo_ref_typeid(r); // The type of ref is: class Rectangle }
If in the above code the Demo_ref_typeid() method receives a reference to a base class that does not support polymorphism (there is no chain of virtual functions), then the type of the base class Area will be obtained.
The implementation of the Demo_ref_typeid() function receives a reference parameter to the base class Area&. The same result can be achieved by taking a pointer parameter to the base class Area*.
After running the program will give the following result
Pointer p points to object of type: class Area Pointer p points to object of type: class Circle Pointer p points to object of type: class Rectangle The type of ref is: class Area The type of ref is: class Circle The type of ref is: class Rectangle
⇑
2.2. The typeid operator for a type (class)
The example shows code that uses the typeid operator to determine the type of an object of some class and variable.
#include <iostream> #include <typeinfo> using namespace std; // A set of classes // Base class class A { // ... }; // Inherited classes class B : public A { // ... }; class C : public B { // ... }; void main(void) { // 1. Create instances of classes B, C B objB; C objC; // 2. Checking what type an objC instance is if (typeid(objC) == typeid(A)) cout << "objC is of type A" << endl; if (typeid(objC) == typeid(B)) cout << "objC is of type B" << endl; if (typeid(objC) == typeid(C)) cout << "objC is of type C" << endl; // + // 3. Checking if a is an integer type int int a; if (typeid(a) == typeid(int)) cout << "Variable a is of type int." << endl; else cout << "Variable a is not of type int" << endl; }
Program result
objC is of type C Variable a is of type int.
⇑
3. An example of using the typeid operator for template classes
The typeid operator can be applied to template classes that operate on some generic type. For each specific instance of the class, a suitable type is formed.
The following is an example of using the typeid() operator for the Point<T> template class.
#include <iostream> #include <typeinfo> using namespace std; // Template class that implements a point on the coordinate plane template <class T> class Point { private: T x, y; public: // Constructor Point(T _x, T _y) : x(_x), y(_y) { } // Access methods T X() { return x; } T Y() { return y; } }; void main(void) { // Declare instances of the Point<T> class for different types Point<int> objInt(8, 9); Point<double> objDouble(7.2, 3.1); // Print object types objInt and objDouble cout << "typeid(objInt) = " << typeid(objInt).name() << endl; cout << "typeid(objDouble) = " << typeid(objDouble).name() << endl; // Determine if objInt and objDouble object types are the same if (typeid(objInt) == typeid(objDouble)) cout << "Types of objInt and objDouble are equal." << endl; else cout << "Types of objInt and objDouble are not equal." << endl; }
Program result
typeid(objInt) = class Point<int> typeid(objDouble) = class Point<double> Types of objInt and objDouble are not equal.
⇑
Related topics
⇑