Casting
Introduction to Casting
Casting is the process of forcing one data type to be converted into another. There more general casts are used as follows:
(type) expression
. For example, when converting from a double to an int:
(int) 5.6
becomes
5
There are 4 other types of casts:
static_cast
const_cast
dynamic_cast
reinterpret_cast
Static Cast
static_cast<Type> (Expression)
This function takes in a type and returns an "equivalent" value of type
Type
. This can be used for non-polymorphic downcasting from a parent pointer to a child pointer. It does not change the value of variable in expression.
Const Cast
const_cast<Type> (Expression)
This is used to explicitly override
const
/
volatile
in a cast. The target type must be the same. It is used to either set or remove the
const
attribute.
void g(int *p);
void f(const int *p) {
g(const_cast(p));
}
Dynamic Cast
dynamic_cast<Type> (Expression)
Dynamic casting is a type-safe form of downcasting by verifying the validity of the cast at runtime. It performs polymorphic downcasting from a parent pointer to a child pointer. If it fails (i.e. pointer does not point to the type specified), it returns
nullptr
. It is safer than static_cast, but less efficient. This only works on polymorphic classes (have at least one virtual method).
Book *pb;
Text *pt = static_cast<Text>(pb)->getTopic(); // might throw error
// alternative
Book *pb;
Text *pt = dynamic_cast<Text>(pb); // nullptr if error
if (pt) cout << pt->getTopic();
else cout << "Not a Text";
Reinterpret Cast
reinterpret_cast<Type> (Expression)
This operator changes a pointer to any other type of pointer. It also allows casting from pointer to an integer type and vice versa. This is an implementation-dependent cast and is unsafe.
Student s;
// Force student to be treated like a turtle :(
Turtle *t = reinterpret_cast<Turtle*>(&s);
Downcasting
Downcasting is generally frowned upon because we might be downcasting into a wrong type. If possible, we should be using polymorphism rather than trying to downcast. If we do have to downcast, however,
dynamic_cast
provides a type-safe downcast operation because it returns a
nullptr
if the cast is not proper.
Pet *b = new Cat; // Upcast
Dog *d1 = dynamic_cast<Dog*>(b); // returns nullptr
Cat *c1 = dynamic_cast<Cat*>(b); // OK
Downcasting References
Downcasting pointers is exception-safe as discussed earlier (returns
nullpre
if wrong type). However, if we try to
dynamic_cast
a reference variable of the wrong type,
dynamic_cast
will throw a
bad_cast
because there is no such thing as a null reference.
RTTI (Run-Time Type Information)
RTTI refers to the ability to provide information about the type of a dynamic-typed object at runtime.
dynamic_cast
is a form of RTTI. We can also use
typeid
(declared in
<typeinfo>
) and
static_cast
to downcast.
typeid
returns a reference to a
std::type_info
object which can be used to compare objects/references/pointers with the desired type using
==
and
!=
.
typeid(obj).name()
returns a string representation of the type name
Circle c;
Shape *s = &c; // Upcast
if (typeid(Circle) == typeid(s)) s = static_cast<Shape*>(&c);
Mechanisms of RTTI with Dynamic Cast
When
dynamic_cast<destination*>(src)
is used:
- Source pointers RTTI info is retrieved
- RTTI info of destination is fetched
- Library routine then determines whether source pointers type is of destination type or base class type
Creating Your Own RTTI
RTTI requires only a virtual function to identify the exact type of the class, and a function to take a pointer to the base type and cast it down to the derived type. This function produces a pointer of the derived type.