19.2.2. The typeid Operator

The second operator provided for RTTI is the typeid operator. The typeid operator allows a program to ask of an expression: What type is your object?


Exercises Section 19.2.1

Exercise 19.3: Given the following class hierarchy in which each class defines a public default constructor and virtual destructor:

class A { /* . . . */ };
class B : public A { /* . . .  */ };
class C : public B { /* . . .  */ };
class D : public B, public A { /* . . .  */ };

which, if any, of the following dynamic_casts fail?

(a) A *pa = new C;
    B *pb = dynamic_cast< B* >(pa);
(b) B *pb = new B;
    C *pc = dynamic_cast< C* >(pb);
(c) A *pa = new D;
    B *pb = dynamic_cast< B* >(pa);

Exercise 19.4: Using the classes defined in the first exercise, rewrite the following code to convert the expression *pa to the type C&:

if (C *pc = dynamic_cast< C* >(pa))
    // use C's members
} else {
    // use A's members
}

Exercise 19.5: When should you use a dynamic_cast instead of a virtual function?


A typeid expression has the form typeid(e) where e is any expression or a type name. The result of a typeid operation is a reference to a const object of a library type named type_info, or a type publicly derived from type_info. § 19.2.4 (p. 831) covers this type in more detail. The type_info class is defined in the typeinfo header.

The typeid operator can be used with expressions of any type. As usual, top-level const2.4.3, p. 63) is ignored, and if the expression is a reference, typeid returns the type to which the reference refers. When applied to an array or function, however, the standard conversion to pointer (§ 4.11.2, p. 161) is not done. That is, if we take typeid(a) and a is an array, the result describes an array type, not a pointer type.

When the operand is not of class type or is a class without virtual functions, then the typeid operator indicates the static type of the operand. When the operand is an lvalue of a class type that defines at least one virtual function, then the type is evaluated at run time.

Using the typeid Operator

Ordinarily, we use typeid to compare the types of two expressions or to compare the type of an expression to a specified type:

Derived *dp = new Derived;
Base *bp = dp;  // both pointers point to a Derived object
// compare the type of two objects at run time
if (typeid(*bp) == typeid(*dp)) {
    // bp and dp point to objects of the same type
}
// test whether the run-time type is a specific type
if (typeid(*bp) == typeid(Derived)) {
    // bp actually points to a Derived
}

In the first if, we compare the dynamic types of the objects to which bp and dp point. If both point to the same type, then the condition succeeds. Similarly, the second if succeeds if bp currently points to a Derived object.

Note that the operands to the typeid are objects—we used *bp, not bp:

// test always fails: the type of bp is pointer to Base
if (typeid(bp) == typeid(Derived)) {
    // code never executed
}

This condition compares the type Base* to type Derived. Although the pointer points at an object of class type that has virtual functions, the pointer itself is not a class-type object. The type Base* can be, and is, evaluated at compile time. That type is unequal to Derived, so the condition will always fail regardless of the type of the object to which bp points.


Image Warning

The typeid of a pointer (as opposed to the object to which the pointer points) returns the static, compile-time type of the pointer.


Whether typeid requires a run-time check determines whether the expression is evaluated. The compiler evaluates the expression only if the type has virtual functions. If the type has no virtuals, then typeid returns the static type of the expression; the compiler knows the static type without evaluating the expression.

If the dynamic type of the expression might differ from the static type, then the expression must be evaluated (at run time) to determine the resulting type. The distinction matters when we evaluate typeid(*p). If p is a pointer to a type that does not have virtual functions, then p does not need to be a valid pointer. Otherwise, *p is evaluated at run time, in which case p must be a valid pointer. If p is a null pointer, then typeid(*p) throws a bad_typeid exception.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.96.86