Run-Time Type Information
Reading: Dietel section 21.7
Dynamic Cast Operator
- We know that a subclass pointer / reference can always be converted to the base class
subclass is-a base class- Conversions in the other direction are generally not safe
base class object may be lacking specialized subclass members- But if the base class object pointed / referred to really is a subclass object, we would like to be able to interpret it as such:
Base* B = new Subclass;
Subclass* S = B; // causes a compiler error, even though safe here
S -> SomeSubclassFunction ( ); // would like to be able to do this- We can use the dynamic_cast operator to check for such situations:
void foo ( Base* B) // prototype may be needed for backward compatibility
{
Subclass* S = dynamic_cast < Subclass * > B;
// run-time check to make sure that *B really is of type Subclass
// if not , the dynamic cast returns the value 0
S -> SomeSubclassFunction ( );
// now allowed if cast succeeded
// S is a Subclass*, can invoke Subclass methods
}
Static Cast Operator
- Dynamic cast involves a run-time check; incurs some overhead
- If we are sure the object being cast is of subclass type, we can use static cast to bypass the run-time check:
Base* B = new Subclass;
Subclass* S = static_cast < Subclass * > B; // no checking; "trusts" programmer
S -> SomeSubclassFunction ( ); // allowed; S is a Subclass *- Behavior is undefined if the object being cast is not of subclass type!
- Both dynamic and static casts respect constness and access specifiers
Cannot convert a subclass object to a private or protected base class
Must use a const_cast to cast away constness
TypeID Capabilities
- Dynamic ( and static ) casts convert between base class and subclass pointers / references
- Sometimes we would like to know the exact type of an object (and not just perform a particular conversion)
Error diagnosis: may want to output the type name of an object involved in an error
May want to check that two operands are of matching type- typeid ( ) function is available for this purpose
void foo ( Shape& r, Shape* p)
{
cout << typeid ( r ) . name ( ) << endl; // Prints type of object referred to
cout << typeid ( *p ) . name ( ) << endl; // Prints type of object pointed to
cout << typeid ( p ) . name ( ) << endl; // Prints "Shape*" -- desired?
}- Functionality of typeid
operators ==, != : Are two types the same / not the same?
const char* name ( ) const; : A C-string representation of the type name
typeid ( ) returns a type_info object ( transparent to users )
throws bad_typeid exception if invoked on a 0 pointer / reference
must #include < typeinfo >- Cautions
C-string name representation is implementation-dependent
May be more than one type_info object for a given type
check for equality with ==, != and not by comparing names