C++

Casting & Conversions

12 question(s)

What are the four C++ named casts?

Beginner
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.
double d = static_cast<double>(5);
Base* b = ...; Derived* dd = dynamic_cast<Derived*>(b);
Real-world example Code review requires named casts so each conversion's intent and risk is explicit and greppable.

Common follow-ups: Why prefer named casts over C-style? | Which cast is runtime-checked?

OOP & Classes Casting & Conversions Casting & Conversions

What is static_cast used for?

Beginner
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.

Common follow-ups: Does static_cast check at runtime? | When is a static_cast downcast unsafe?

Casting & Conversions Type Deduction & auto Casting & Conversions

What is dynamic_cast and when do you use it?

Intermediate
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.

Common follow-ups: What does it return on failure for a pointer? | Why must the base be polymorphic?

OOP & Classes Casting & Conversions Casting & Conversions

What is reinterpret_cast and why is it dangerous?

Intermediate
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.

Common follow-ups: What does it actually change? | Why can it cause UB?

Undefined Behavior Casting & Conversions Casting & Conversions

Why are C-style casts discouraged in C++?

Advanced
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.

Common follow-ups: What sequence does a C-style cast try? | Why are named casts searchable?

Casting & Conversions Undefined Behavior Casting & Conversions

What is the difference between implicit and explicit conversions?

Beginner
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.

Common follow-ups: What does explicit prevent? | Which functions can trigger implicit conversion?

OOP & Classes Casting & Conversions Casting & Conversions

What is the explicit keyword and why use it?

Intermediate
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.

Common follow-ups: Which conversions does it block? | When would you allow implicit conversion?

OOP & Classes Casting & Conversions Casting & Conversions

What is a user-defined conversion operator?

Advanced
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.

Common follow-ups: Why mark conversion operators explicit? | What is the safe-bool idiom?

Operator Overloading Casting & Conversions Casting & Conversions

What is narrowing conversion and how does brace initialization help?

Intermediate
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.

Common follow-ups: Why does {} reject narrowing? | Give an example of a narrowing conversion.

Casting & Conversions Type Deduction & auto Casting & Conversions

What is the difference between static_cast and dynamic_cast for downcasting?

Advanced
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.

Common follow-ups: Which is safe but slower? | What does static_cast risk on a wrong type?

OOP & Classes Undefined Behavior Casting & Conversions