Inheritance/Polymorphism  «Prev  Next»
Lesson 16 Runtime Type Identification
Objective The typeid operator and type_info class

C++ typeid Operator instead of the virtual function

This page asks you to use the typeid operator instead of the virtual function you wrote to return the name of a shape as a char* value. The operator typeid() can be applied to a type name or to an expression to determine the exact type of the argument. The operator returns a reference to the class type_info, which is supplied by the system and is defined in the header file type_info.h.
  • Possible arguments of typeid()
    Some possible arguments of typeid() are
    1. a reference to a class
    2. a pointer argument, dereferenced with *

C++ typeid() Pointer Argument

If the typeid() argument is a base class pointer, while the object is of a type derived from that base class, a reference for the derived class is the result. The argument must be a pointer to the base class with virtual functions. Otherwise, the result is the type_info of the base class. The pointer must be dereferenced so that the object it points to is used. Without dereferencing the pointer, the result will be the type_info for the pointer, not what it points to.
typeid allows to check the type of an expression:
typeid (expression)

This operator returns a reference to a constant object of type type_info that is defined in the standard header file < typeinfo > . This returned value can be compared with another one using operators == and != or can serve to obtain a null-terminated character sequence representing the data type or class name by using its name() member.

Let’s break it down step-by-step with some explanation and an example to solidify the concepts. Key Points about typeid and Polymorphism
  1. Polymorphism Requirement: For typeid to return the type information of the actual (derived) object rather than the static type of the pointer, the base class must have at least one virtual function. This enables runtime type identification (RTTI) through polymorphism. Without virtual functions, the type is resolved statically at compile time, and you’ll get the type_info of the base class (or pointer type, if not dereferenced).
  2. Pointer vs. Dereferenced Pointer:
    • If you apply typeid directly to a base class pointer (e.g., typeid(ptr)), you get the type_info of the pointer type itself (e.g., Base*), not the object it points to.
    • If you dereference the pointer (e.g., typeid(*ptr)), typeid examines the actual object at runtime and returns the type_info of the derived class, provided the base class supports polymorphism.
  3. Abstract Base Classes: These often come into play here because they typically have pure virtual functions (e.g., virtual void func() = 0;), making them polymorphic by nature. This setup is common when using typeid with inheritance hierarchies.

Example Code Here’s a concrete example to illustrate:
#include <iostream>
#include <typeinfo>

class Base {
public:
    virtual void speak() { // Virtual function makes Base polymorphic
        std::cout << "I am Base\n";
    }
    virtual ~Base() = default; // Virtual destructor (good practice)
};

class Derived : public Base {
public:
    void speak() override {
        std::cout << "I am Derived\n";
    }
};

int main() {
    Base* ptr = new Derived(); // Base pointer to a Derived object

    // Without dereferencing: type of the pointer itself
    std::cout << "typeid(ptr): " << typeid(ptr).name() << "\n"; // Outputs "P4Base" (Base*)

    // Dereferenced: type of the object it points to
    std::cout << "typeid(*ptr): " << typeid(*ptr).name() << "\n"; // Outputs "7Derived" (Derived)

    // Compare with a non-polymorphic case
    class NonPolyBase {
    public:
        void speak() {}
    };
    class NonPolyDerived : public NonPolyBase {};

    NonPolyBase* np_ptr = new NonPolyDerived();
    std::cout << "typeid(*np_ptr): " <<  typeid(*np_ptr).name() <<  "\n"; // Outputs "11NonPolyBase" (static type)

    delete ptr;
    delete np_ptr;
    return 0;
}
Explanation of Output
  • typeid(ptr): Returns Base* (mangled name varies by compiler, e.g., P4Base on GCC). This is the static type of the pointer, not the object.
  • typeid(*ptr): Returns Derived (e.g., 7Derived). The virtual function in Base enables RTTI, so dereferencing gives the dynamic type of the object.
  • typeid(*np_ptr): Returns NonPolyBase. Without virtual functions, there’s no polymorphism, so typeid uses the static type of the pointer’s declared type, ignoring the derived object.

Why Virtual Functions Matter The presence of virtual functions ensures a virtual table (vtable) is created for the class. The vtable allows the runtime system to determine the actual type of an object via its pointer or reference. When typeid is invoked on a dereferenced polymorphic pointer, it queries this runtime mechanism to fetch the type_info of the object, not just the pointer’s declared type.
Dereferencing Caveat If the pointer is nullptr, typeid(*ptr) will still compile and run but may result in undefined behavior or throw a std::bad_typeid exception in some implementations when dereferencing a null pointer to a polymorphic type. So, always ensure the pointer is valid when dereferencing.
Summary
  • typeid(*base_ptr) → type_info of the derived object if Base has virtual functions.
  • typeid(base_ptr) → type_info of the pointer type (Base*).
  • No virtual functions → static type (Base) regardless of the object.

If you use MSVC, select the Run-Time Type Information (RTTI) option in order to enable the typeinfo.h utilities.
The class type_info provides a name() member function returning a string that is the type name. It also provides overloadedequality operators. Remember to check the local implementation for the complete interface of this class.
Base* bptr;
.....
//print the type name of what bptr currently points at
cout << typeid(bptr).name() << endl;
.....
if (typeid(bptr) == typeid(Derived)) {
//do something appropriate for Derived
.....
}

Typeid Operator - Exercise

Click the Exercise link below to use the typeid operator instead of the virtual function you wrote that returns the name of a shape as a char* value.
Typeid Operator - Exercise

SEMrush Software