CodeNebula
C++98corebeginner

Typeid

C++98 · The Foundation · Compiler flag: -std=c++98

Explanation

Operator to get type information of an object at runtime.

Real-World Scenario

Display variable types in a diagnostic tool.

Quick Snippet

snippet.cpp
#include <typeinfo> cout << typeid(int).name();

Full Example

typeid.cpp
// CodeNebula - C++98 Example: typeid Operator
// Compile: g++ -std=c++98 -Wall -Wextra -o example typeid.cpp

// The typeid operator returns a const reference to std::type_info, providing
// runtime type information. This example focuses on typeid with polymorphic
// types, type_info::name(), type comparison, and the difference between
// static and dynamic type resolution.

#include <iostream>
#include <typeinfo>   // Required for typeid, type_info, bad_typeid
#include <string>

// ------------------------------------------------------------------
// Polymorphic hierarchy (has virtual functions -> dynamic typeid)
// ------------------------------------------------------------------
class Vehicle {
public:
    virtual std::string describe() const { return "Vehicle"; }
    virtual ~Vehicle() {}
};

class Car : public Vehicle {
public:
    std::string describe() const { return "Car"; }
};

class ElectricCar : public Car {
public:
    std::string describe() const { return "ElectricCar"; }
};

class Truck : public Vehicle {
public:
    std::string describe() const { return "Truck"; }
};

// ------------------------------------------------------------------
// Non-polymorphic hierarchy (no virtual functions -> static typeid)
// ------------------------------------------------------------------
class BaseNP {
public:
    int x;
    BaseNP() : x(0) {}
};

class DerivedNP : public BaseNP {
public:
    int y;
    DerivedNP() : y(0) {}
};

// ------------------------------------------------------------------
// Helper: print type info
// ------------------------------------------------------------------
void printTypeInfo(const std::type_info& ti) {
    std::cout << "  name():  " << ti.name() << std::endl;
}

int main() {
    std::cout << "=== C++98 typeid Operator ===" << std::endl;

    // --- 1. typeid with fundamental types ---
    std::cout << "\n--- 1. Fundamental types ---" << std::endl;
    std::cout << "typeid(int).name()     = " << typeid(int).name() << std::endl;
    std::cout << "typeid(double).name()  = " << typeid(double).name() << std::endl;
    std::cout << "typeid(char).name()    = " << typeid(char).name() << std::endl;
    std::cout << "typeid(bool).name()    = " << typeid(bool).name() << std::endl;
    std::cout << "typeid(float*).name()  = " << typeid(float*).name() << std::endl;
    // Note: name() output is implementation-defined (e.g., "i", "d" on GCC)

    // --- 2. typeid comparison ---
    std::cout << "\n--- 2. Type comparison ---" << std::endl;
    int a = 10;
    double b = 3.14;
    int c = 20;

    std::cout << "typeid(a) == typeid(c): "
              << (typeid(a) == typeid(c) ? "true" : "false") << std::endl;
    // Expected: true (both are int)

    std::cout << "typeid(a) == typeid(b): "
              << (typeid(a) == typeid(b) ? "true" : "false") << std::endl;
    // Expected: false (int vs double)

    std::cout << "typeid(a) == typeid(int): "
              << (typeid(a) == typeid(int) ? "true" : "false") << std::endl;
    // Expected: true

    // --- 3. Polymorphic types: dynamic type resolution ---
    std::cout << "\n--- 3. Polymorphic types (dynamic typeid) ---" << std::endl;
    Car car;
    ElectricCar eCar;
    Truck truck;

    // Through base pointer, typeid gives the DYNAMIC (actual) type
    Vehicle* vehicles[3];
    vehicles[0] = &car;
    vehicles[1] = &eCar;
    vehicles[2] = &truck;

    for (int i = 0; i < 3; ++i) {
        std::cout << "vehicles[" << i << "]: "
                  << "typeid.name() = " << typeid(*vehicles[i]).name()
                  << ", describe() = " << vehicles[i]->describe()
                  << std::endl;
    }
    // typeid(*vehicles[i]) resolves to the actual runtime type

    // --- 4. Static type vs dynamic type ---
    std::cout << "\n--- 4. Static vs dynamic type ---" << std::endl;

    Vehicle* vp = &eCar;

    // typeid of the POINTER (static type) vs typeid of the OBJECT (dynamic type)
    std::cout << "typeid(vp).name()  = " << typeid(vp).name()
              << "  (pointer type - static)" << std::endl;
    std::cout << "typeid(*vp).name() = " << typeid(*vp).name()
              << "  (object type - dynamic)" << std::endl;

    // The pointer type is always Vehicle*, regardless of what it points to
    // The dereferenced type reflects the actual object (ElectricCar)

    std::cout << "\ntypeid(*vp) == typeid(ElectricCar): "
              << (typeid(*vp) == typeid(ElectricCar) ? "true" : "false") << std::endl;
    // Expected: true

    std::cout << "typeid(*vp) == typeid(Car): "
              << (typeid(*vp) == typeid(Car) ? "true" : "false") << std::endl;
    // Expected: false (exact type is ElectricCar, not Car)

    std::cout << "typeid(*vp) == typeid(Vehicle): "
              << (typeid(*vp) == typeid(Vehicle) ? "true" : "false") << std::endl;
    // Expected: false

    // --- 5. Non-polymorphic types: static type resolution ---
    std::cout << "\n--- 5. Non-polymorphic types (static typeid) ---" << std::endl;

    DerivedNP derived;
    BaseNP* bp = &derived;

    // Without virtual functions, typeid uses the STATIC (declared) type
    std::cout << "typeid(*bp).name() = " << typeid(*bp).name()
              << "  (STATIC type - BaseNP)" << std::endl;
    std::cout << "typeid(derived).name() = " << typeid(derived).name()
              << "  (known at compile time)" << std::endl;

    std::cout << "typeid(*bp) == typeid(BaseNP): "
              << (typeid(*bp) == typeid(BaseNP) ? "true" : "false") << std::endl;
    // Expected: true (uses static type since no virtual functions)

    std::cout << "typeid(*bp) == typeid(DerivedNP): "
              << (typeid(*bp) == typeid(DerivedNP) ? "true" : "false") << std::endl;
    // Expected: false (static type is BaseNP)

    // --- 6. type_info::before() ---
    std::cout << "\n--- 6. type_info::before() ---" << std::endl;
    const std::type_info& tiCar = typeid(Car);
    const std::type_info& tiTruck = typeid(Truck);

    // before() provides a consistent ordering (implementation-defined)
    std::cout << "Car before Truck: "
              << (tiCar.before(tiTruck) ? "yes" : "no") << std::endl;
    std::cout << "Truck before Car: "
              << (tiTruck.before(tiCar) ? "yes" : "no") << std::endl;
    // One must be true, the other false (total ordering)

    // --- 7. typeid with expressions ---
    std::cout << "\n--- 7. typeid with expressions ---" << std::endl;
    int x = 5;
    double y = 2.5;

    std::cout << "typeid(x + x).name() = " << typeid(x + x).name() << std::endl;
    // Expected: int
    std::cout << "typeid(x + y).name() = " << typeid(x + y).name() << std::endl;
    // Expected: double (int promoted to double)
    std::cout << "typeid(true).name()  = " << typeid(true).name() << std::endl;
    // Expected: bool

    // --- 8. Using typeid for a simple type-based dispatch ---
    std::cout << "\n--- 8. Type-based dispatch ---" << std::endl;
    for (int i = 0; i < 3; ++i) {
        const std::type_info& ti = typeid(*vehicles[i]);

        if (ti == typeid(Car)) {
            std::cout << "Processing a Car..." << std::endl;
        } else if (ti == typeid(ElectricCar)) {
            std::cout << "Processing an ElectricCar (check battery!)..." << std::endl;
        } else if (ti == typeid(Truck)) {
            std::cout << "Processing a Truck (check cargo!)..." << std::endl;
        }
    }

    return 0;
}

/*
Expected Output:
=== C++98 typeid Operator ===

--- 1. Fundamental types ---
typeid(int).name()     = i          (GCC) or "int" (MSVC)
typeid(double).name()  = d          (GCC) or "double" (MSVC)
typeid(char).name()    = c          (GCC) or "char" (MSVC)
typeid(bool).name()    = b          (GCC) or "bool" (MSVC)
typeid(float*).name()  = Pf         (GCC) or "float *" (MSVC)

--- 2. Type comparison ---
typeid(a) == typeid(c): true
typeid(a) == typeid(b): false
typeid(a) == typeid(int): true

--- 3. Polymorphic types (dynamic typeid) ---
vehicles[0]: typeid = Car, describe() = Car
vehicles[1]: typeid = ElectricCar, describe() = ElectricCar
vehicles[2]: typeid = Truck, describe() = Truck

--- 4. Static vs dynamic type ---
typeid(vp)  = Vehicle*  (pointer - static)
typeid(*vp) = ElectricCar  (object - dynamic)
typeid(*vp) == typeid(ElectricCar): true
typeid(*vp) == typeid(Car): false
typeid(*vp) == typeid(Vehicle): false

--- 5. Non-polymorphic types (static typeid) ---
typeid(*bp) = BaseNP  (STATIC type)
typeid(*bp) == typeid(BaseNP): true
typeid(*bp) == typeid(DerivedNP): false

--- 6. type_info::before() ---
(ordering is implementation-defined)

--- 7. typeid with expressions ---
typeid(x + x) = int
typeid(x + y) = double
typeid(true)  = bool

--- 8. Type-based dispatch ---
Processing a Car...
Processing an ElectricCar (check battery!)...
Processing a Truck (check cargo!)...
*/
Run command
g++ -std=c++98 -Wall -Wextra -o example typeid.cpp