typeid is the one of the meager offering of runtime type information hierarchy functionality. what it offers is the ability to determine at runtime the real type of an object (a pointer is a special type of variable, which we will lsee shorty in this post )
what is the typeid operator used for?
it is used in advanced programming developement, when building debugger for example, or it is used to deal with persistent object through a pointer or a reference to a base class.
The program needs to find out the actual type of the object manipulated to list the properties of an object properly during a debugging session or to store and retrieve an object property
During a debugging session or to store and retrieve an object property properly to find out the actual type of an object, the typeid operator can be used.
For better describe what we will describe, here is the class hiearchy that we will use in this example.
class employee
{
};
class manager : public employee
{};
class programmer : public employee
{
};
so, in the simplest case, what is the output of the followiong.
void typeid_test() {
programmer obj ;
programmer &re = obj;
// we look at name() in the subsection on type_info
// below, name() returns the C-style string: "programmer"
cout << typeid(re).name() << endl;
}
the typeid can accept two types of operand, one is an expression and the other is the name of the type. Let's first see the first type of operand (the later case will be covered in example later) .
/**
* the operand of the typeid operator can be expression or type names of any type
*
*/
void typeid_operand()
{
int iobj;
cout << typeid(iobj).name() << endl; // print : ints
cout <<typeid(8.16).name() << endl; // prints : double
}
when the oeprand to typeid operator is a class, but not a class of virtual function, the result of the typeid operator is well, not the type of underlying object.
/**
* if the typeid operand is a class type, but not of a class type with virtual functions. then the typeid operator indicates the type of
* the operand is well, not the type of the underlying object
*/
class Base
{
};
class Derived : public Base { };
void typeid_non_virtual_class()
{
Derived dobj;
Base *pb = &dobj;
cout << typeid(*pb).name() << endl; // prints : Base
}
but, if the class does have virtual function, then the real derived object will be retrieved and its true type will be returned.
/*
* if the typeid oeprand is a class type , where if class to be examined is of virutal functions, then the
* real derived classes will be returned.
*/
void typeid_result_virtual_class()
{
employee *pe = new manager();
employee &re = *pe;
if (typeid(*pe) == typeid(manager)) cout << "typeid(*pe) == typeid(manager)" << endl; // true
if (typeid(re) == typeid(employee)) cout << "typeid(re) == typeid(employee)" << endl; // true
if (typeid(&re) == typeid(employee *)) cout << "typeid(&re) == typeid(employee *)" << endl; // true
if (typeid(&re) == typeid(manager *)) cout << "typeid(&re) == typeid(manager *)" << endl; // false
}
you may have seen already that there are some difference between the object and poiner, the pointer type itself is fixed, so to get the dynamic behavior of typeid, you'd better pass in the real object or reference (which will be treated as the data object)
type_info class
You may find the type_info class declaration as follow. actually the real implementation can vary from implemenation to implemenation.
class type_info {
private:
type_info(const type_info&);
type_info& operator = (const type_info &);
public:
virtual ~type_info();
int operator ==(const type_info&) const;
int operator!=(const type_info &) const;
const char *name() const;
};
the only way to construct the type_info object is to use the typeid operator.
what is containd in the type_info class is implementation dependant. the name() const char * is the only member guaranteed to be provided by all C++ implementation , though it is possible that implementaion dependant may provide additional support. what can be added, basically any information that a compiler can provide about a type about a type can be added.
- a list of the class member functions.
- what the layout of an object of this clases type looks like in storage, that is , how the member and base subobjects are mapped
class extended_type_info :public type_info {};
typedef extended_type_info eti;
void func(employee * p)
{
// downcast from type_info * to extended_type_info*
if (const eti * eti_p = dynamic_cast<const eti *>(&typeid(*p))) {
// if dynamic_cast succeeds
// use extended_type_info information through eti_p
} else{
// if dynamically fails
// use standard type_info information
}
}