double d = static_cast<double>(5);
Base* b = ...; Derived* dd = dynamic_cast<Derived*>(b);
C++
Topics in this category
Casting & Conversions
Compilation & Linking
Concepts & Constraints
Concurrency
Const Correctness
Constexpr & Compile-Time
Coroutines
Enums & Enum Classes
Exception Handling
I/O Streams
Lambda Expressions
Memory Management
Modern C++
Move Semantics
Namespaces
OOP & Classes
Operator Overloading
Preprocessor & Macros
RAII & Smart Pointers
Ranges & Views
C++
Casting & Conversions
C++ provides static_cast (compile-time, related-type conversions), dynamic_cast (safe downcasting in polymorphic hierarchies, checked at runtime), const_cast (add/remove const/volatile), and reinterpret_cast (low-level bit reinterpretation). They replace the C-style cast with clearer intent and safer, more searchable conversions.
Real-world example
Code review requires named casts so each conversion's intent and risk is explicit and greppable.
OOP & Classes
Casting & Conversions
Casting & Conversions
static_cast performs well-defined conversions known at compile time: numeric conversions (int to double), converting between related pointer types in a hierarchy (up or down without runtime check), void* to typed pointer, and explicit calls to conversion operators/constructors. It does no runtime checking, so an invalid downcast is undefined behavior.
int i = 7;
double d = static_cast<double>(i) / 2; // 3.5
Real-world example
static_cast converts an enum to its underlying int for arithmetic or indexing.
Casting & Conversions
Type Deduction & auto
Casting & Conversions
dynamic_cast safely converts pointers/references within a polymorphic class hierarchy (the base must have a virtual function), checking at run time using RTTI. On a pointer, it returns nullptr if the cast is invalid; on a reference, it throws std::bad_cast. Use it for safe downcasting when you must determine an object's dynamic type.
Base* b = getShape();
if (auto* c = dynamic_cast<Circle*>(b)) c->radius();
Real-world example
A rendering loop dynamic_casts base pointers to handle specific shape subtypes safely.
OOP & Classes
Casting & Conversions
Casting & Conversions
reinterpret_cast reinterprets the bit pattern of one type as another (e.g., pointer to integer, or between unrelated pointer types). It performs no conversion of value, only a compile-time reinterpretation, and misusing it easily leads to undefined behavior (alignment violations, strict-aliasing breaks). It's for low-level code (hardware, serialization) and should be used rarely and carefully.
auto addr = reinterpret_cast<std::uintptr_t>(ptr); // pointer to int
Real-world example
Low-level driver code uses reinterpret_cast to view a device register address as an integer.
Undefined Behavior
Casting & Conversions
Casting & Conversions
A C-style cast (int)x tries static_cast, then const_cast, then reinterpret_cast (and combinations) in sequence, so it can silently perform a dangerous reinterpret or strip const without you realizing. The named casts express precise intent, are easy to search for, and are checked more strictly, making code safer and clearer.
int* p = (int*)someObj; // could be a hidden reinterpret_cast
Real-world example
A C-style cast accidentally reinterprets an unrelated pointer; a named cast would have failed to compile.
Casting & Conversions
Undefined Behavior
Casting & Conversions
Implicit conversions happen automatically (e.g., int to double, or via a non-explicit constructor/conversion operator). Explicit conversions require a cast or an explicit constructor call. Marking single-argument constructors and conversion operators explicit prevents surprising implicit conversions that can hide bugs.
struct S { explicit S(int); };
S a = 5; // error: explicit
S b(5); // ok
Real-world example
Marking a constructor explicit stops an int from silently becoming an object in an overload call.
OOP & Classes
Casting & Conversions
Casting & Conversions
explicit prevents a constructor or conversion operator from being used for implicit conversions, requiring direct/explicit invocation. It avoids surprising conversions—like a class accidentally constructed from an int in a function call—that cause ambiguity or bugs. Best practice marks single-argument constructors explicit unless implicit conversion is genuinely desired.
struct Meters { explicit Meters(double); };
void f(Meters);
// f(3.0); // error, good
f(Meters(3.0)); // explicit, clear
Real-world example
explicit on a Distance(double) constructor prevents a raw double from silently becoming a Distance.
OOP & Classes
Casting & Conversions
Casting & Conversions
A conversion operator (operator T() const) lets a class object be converted to another type T implicitly or explicitly. It enables classes to integrate with code expecting T, but implicit conversion operators can cause surprising conversions and ambiguity, so they're often marked explicit (e.g., explicit operator bool() for use in conditions only).
struct Handle {
explicit operator bool() const { return valid; }
bool valid = false;
};
if (h) { /* uses explicit operator bool */ }
Real-world example
A smart-handle type provides explicit operator bool so it works in if-conditions but not in arithmetic.
Operator Overloading
Casting & Conversions
Casting & Conversions
A narrowing conversion loses information (e.g., double to int, or a larger int to a smaller one). Brace (list) initialization {} disallows narrowing conversions, turning a silent data-losing conversion into a compile error, which makes initialization safer than the older = or () forms for catching such bugs.
int a = 3.9; // ok, silently truncates to 3
int b {3.9}; // error: narrowing conversion
Real-world example
Using brace initialization catches an accidental double-to-int truncation at compile time.
Casting & Conversions
Type Deduction & auto
Casting & Conversions
static_cast downcasts without any runtime check—fast, but undefined behavior if the object isn't actually of the target type. dynamic_cast checks the actual dynamic type at runtime (using RTTI) and returns nullptr (pointers) or throws (references) if the cast is invalid, making it safe but slower and requiring a polymorphic base. Use dynamic_cast when correctness of the type isn't guaranteed.
Derived* d1 = static_cast<Derived*>(base); // unchecked
Derived* d2 = dynamic_cast<Derived*>(base); // nullptr if wrong
Real-world example
static_cast is used when the type is known; dynamic_cast when handling heterogeneous base pointers safely.
OOP & Classes
Undefined Behavior
Casting & Conversions