oops · high
Upcasting, Downcasting, dynamic_cast & RTTI
Moving around a class hierarchy safely: implicit upcasting, checked downcasting with dynamic_cast (nullptr vs bad_cast), why the type must be polymorphic, how it differs from an unchecked static_cast, what RTTI/typeid give you, and why reaching for dynamic_cast often signals a missing virtual function.
Upcasting derived->base is implicit and always safe. Downcasting base->derived needs a CHECKED `dynamic_cast` (requires a polymorphic type); it returns nullptr for pointers / throws bad_cast for references on a wrong type. `static_cast` downcasts are unchecked (UB if wrong). dynamic_cast & typeid use RTTI. Frequent downcasting is usually a design smell — prefer a virtual call.
The code
struct Animal { virtual ~Animal() = default;}; // polymorphic (has a vtable)struct Dog : Animal { void bark();};struct Cat : Animal {};
Animal* a = new Dog; // upcast: implicit, always safeDog* d = dynamic_cast<Dog*>(a); // downcast: checked -> non-nullCat* c = dynamic_cast<Cat*>(a); // checked -> nullptr (not a Cat)Dog& r = dynamic_cast<Dog&>(*a); // reference form -> throws on failDog* s = static_cast<Dog*>(a); // UNCHECKED -> UB if a isn't a DogWhat this lesson walks through
- 01Upcast — derived → base is implicit and always safe
- 02Downcast to the real type → dynamic_cast succeeds
- 03Wrong type → nullptr (ptr) / throw (ref); static_cast = UB
An object's real type is Dog. Storing it in an Animal* (upcast) is implicit and always safe: a Dog IS-A Animal. The pointer's static type narrows; the object is unchanged.
See it animated — step by step, at your own pace
Unlock the full interactive walkthrough of Upcasting, Downcasting, dynamic_cast & RTTI and 100+ animated C++ interview lessons.