Skip to content
  • Casts & RTTI · C++

Casts & RTTI

LearnViaNotes @learnvianotes· 3 min read

C++ replaces the all-powerful C cast with four named casts, each saying what you're doing. dynamic_cast and typeid use Run-Time Type Information.

The four casts

CastCheckedUse
static_cast<T>Compile timeNumeric conversions, void* → T*, up-casts, down-casts you know are valid, enum ↔ int
dynamic_cast<T>Run timeSafe down-cast/cross-cast in a polymorphic hierarchy; nullptr (pointers) or std::bad_cast (references) on failure
const_cast<T>Compile timeRemove/add const — e.g. calling a legacy API that forgot const. Modifying a truly const object is UB
reinterpret_cast<T>NoneReinterpret bits: pointer ↔ integer, unrelated pointer types. Platform-specific

static_cast

C++
#include <iostream>
enum class Level { Low = 1, High = 3 };
int main() {
    double avg = static_cast<double>(7) / 2;
    int lvl = static_cast<int>(Level::High);
    char c = static_cast<char>(65);
    void* vp = &lvl;
    int* ip = static_cast<int*>(vp);
    std::cout << avg << ' ' << lvl << ' ' << c << ' ' << *ip << '\n';
}
Output
3.5 3 A 3

dynamic_cast

C++
#include <iostream>
#include <memory>
#include <typeinfo>
#include <vector>

struct Animal { virtual ~Animal() = default; };     // must be polymorphic
struct Dog : Animal { void fetch() const { std::cout << "fetching\n"; } };
struct Cat : Animal {};

int main() {
    std::vector<std::unique_ptr<Animal>> zoo;
    zoo.push_back(std::make_unique<Dog>());
    zoo.push_back(std::make_unique<Cat>());
    for (const auto& a : zoo) {
        if (auto* d = dynamic_cast<Dog*>(a.get())) d->fetch();     // nullptr if not a Dog
        else std::cout << "not a dog\n";
    }
    Cat cat;
    Animal& ref = cat;
    try {
        Dog& d = dynamic_cast<Dog&>(ref);                         // reference form throws
        d.fetch();
    } catch (const std::bad_cast&) {
        std::cout << "bad_cast\n";
    }
}
Output
fetching
not a dog
bad_cast

typeid

C++
#include <iostream>
#include <typeinfo>
struct Base { virtual ~Base() = default; };
struct Derived : Base {};
struct NonPoly {};
struct NonPolyDerived : NonPoly {};
int main() {
    Derived d;
    Base& b = d;
    NonPolyDerived npd;
    NonPoly& np = npd;
    std::cout << (typeid(b) == typeid(Derived)) << ' ' << (typeid(np) == typeid(NonPolyDerived)) << '\n';
    std::cout << typeid(int).name() << ' ' << typeid(double).name() << '\n';   // implementation-defined names
}
Output
1 0
i d

const_cast & reinterpret_cast

C++
#include <cstdint>
#include <cstring>
#include <iostream>

void legacyPrint(char* s) { std::cout << s << '\n'; }   // doesn't modify, but isn't const-correct

int main() {
    const char* msg = "hello";
    legacyPrint(const_cast<char*>(msg));                 // OK only because legacyPrint doesn't write

    int value = 0x01020304;
    auto addr = reinterpret_cast<std::uintptr_t>(&value);   // pointer → integer
    std::cout << (addr % alignof(int)) << '\n';

    float f = 1.0f;
    std::uint32_t bits;
    std::memcpy(&bits, &f, sizeof bits);                 // the safe way to inspect bits (or std::bit_cast)
    std::cout << std::hex << bits << '\n';
}
Output
hello
0
3f800000

Why avoid C-style casts in C++?

static_cast vs dynamic_cast for down-casting?

Free for students and teachers

Write notes like this one

Cards for every idea, quizzes and flashcards, read aloud — on the web and your phone.

Something wrong with this note? Open it to report