Type Casting
Type casting converts a value from one type to another. C++ performs some conversions automatically (implicit conversions) and lets you request others explicitly (casts). Understanding the difference — and which cast to reach for — is essential for writing safe, predictable code.
Implicit Conversions
int
into a double.
int wholeNumber = 5; double result = wholeNumber; // implicit conversion: int -> double, result is 5.0 double pi = 3.14; int truncated = pi; // implicit conversion: double -> int, truncated is 3 (data loss!)
C-Style Casts
(int)x. It compiles
down to whichever of static_cast, const_cast, or
reinterpret_cast happens to apply — silently and without telling
you which one it picked.
double price = 19.99; int cents = (int)(price * 100); // C-style cast
static_cast, const_cast, and even reinterpret_cast behavior in one expression. It gives the compiler no way to warn you if you accidentally cast away const-ness or reinterpret unrelated pointer types. Modern C++ casts are narrower and safer precisely because each one only does one specific job.Modern C++ Casts
Cast | Purpose | When to Use |
|---|---|---|
static_cast<T>(x) | Well-defined conversions checked at compile time | Numeric conversions, upcasting in a class hierarchy, explicit conversions between related types |
dynamic_cast<T>(x) | Safe downcasting in a polymorphic class hierarchy, checked at runtime | Downcasting a base pointer/reference to a derived type when you are not sure it will succeed |
const_cast<T>(x) | Adds or removes | Calling a legacy API that is not const-correct (rare, use sparingly) |
reinterpret_cast<T>(x) | Reinterprets the raw bit pattern as a different, often unrelated, type | Low-level code: pointer/integer conversions, hardware or binary protocol work |
Worked Example: static_cast for Numeric Conversion
#include <iostream>
int main() {
double price = 19.99;
// static_cast clearly documents intent: "I mean to convert this on purpose"
int cents = static_cast<int>(price * 100);
std::cout << cents << std::endl; // 1999
return 0;
}Worked Example: dynamic_cast for Safe Downcasting
dynamic_cast is the safe way to convert a base-class pointer or
reference back to a derived type. It requires the base class to be
**polymorphic** (have at least one virtual function) and checks at
runtime whether the conversion is actually valid, returning nullptr
(for pointers) if it is not. We cover polymorphism in depth on its own page —
this is a preview of how the casts connect.
#include <iostream>
class Animal {
public:
virtual ~Animal() = default; // must be polymorphic for dynamic_cast to work
};
class Dog : public Animal {
public:
void bark() const { std::cout << "Woof!" << std::endl; }
};
int main() {
Animal* animal = new Dog();
// Safe downcast: returns nullptr if animal isn't actually a Dog
if (Dog* dog = dynamic_cast<Dog*>(animal)) {
dog->bark();
} else {
std::cout << "Not a Dog!" << std::endl;
}
delete animal;
return 0;
}static_cast when you already know a conversion is valid (it has no runtime cost). Reach for dynamic_cast only when you genuinely need a runtime check, since it does incur a small performance cost.