Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

  1. Home
  2. C++ Dictionary
  3. nullptr / static_cast / dynamic_cast

nullptr / static_cast / dynamic_cast

C++ provides nullptr for representing null pointer values, and four cast operators (static_cast / dynamic_cast / reinterpret_cast / const_cast) for type conversions. C-style casts ((type)expr) do not make the conversion intent clear at a glance, so C++ encourages using the appropriate named cast operator for each purpose.

Syntax

// ----------------------------------------
// nullptr: null pointer constant (C++11 and later)
// ----------------------------------------
// Use nullptr instead of NULL macro (integer 0)
// nullptr is of type nullptr_t and represents an uninitialized pointer state
int* p = nullptr;
if (p == nullptr) { /* ... */ }

// ----------------------------------------
// static_cast: converts types at compile time
// ----------------------------------------
double d = 3.14;
int i = static_cast<int>(d);  // double to int (truncates decimal)

// Downcast: base class pointer to derived class pointer (no runtime type check)
// Base* base = new Derived();
// Derived* derived = static_cast<Derived*>(base);

// ----------------------------------------
// dynamic_cast: converts with runtime type safety check
// ----------------------------------------
// Used for downcasting polymorphic classes (with virtual functions)
// Returns nullptr on failure for pointers; throws std::bad_cast for references
// Base* base = new Derived();
// Derived* derived = dynamic_cast<Derived*>(base);
// if (derived == nullptr) { /* cast failed */ }

// ----------------------------------------
// reinterpret_cast: reinterprets bit representation as another type
// ----------------------------------------
// For pointer-integer conversions and unrelated pointer type conversions
// Limit to low-level programming

// ----------------------------------------
// const_cast: adds or removes const/volatile qualifiers
// ----------------------------------------
// Only safe when the original variable is not const

Cast Operator Reference

Operator / KeywordDescription
nullptrType-safe null pointer constant. Represents uninitialized pointer state. Used as a replacement for NULL (integer 0) from C++11 onward.
static_cast<T>(expr)Performs compile-time type conversions. Used for numeric type conversions and pointer conversions between base and derived classes. No runtime type check.
dynamic_cast<T>(expr)Performs downcasting with runtime type safety check. Only usable with polymorphic classes (those with virtual functions). Returns nullptr on failure for pointers, throws std::bad_cast for references.
reinterpret_cast<T>(expr)Forcibly reinterprets the bit representation as another type. Used for pointer-integer conversions and low-level type conversions. Use locations should be minimized.
const_cast<T>(expr)Adds or removes const or volatile qualifiers. This is the only cast that can modify const. Only safe for writing when the original variable is not const.

Sample Code

dragon_ball_cast.cpp
#include <iostream>
#include <string>
#include <vector>

// Base class: Fighter (has virtual functions, so dynamic_cast is usable)
class Fighter {
protected:
    std::string name;
    int powerLevel;

public:
    Fighter(const std::string& name, int powerLevel)
        : name(name), powerLevel(powerLevel) {}

    virtual void showInfo() const {
        std::cout << "[Fighter] " << name
                  << "  Power: " << powerLevel << std::endl;
    }

    std::string getName() const { return name; }
    int getPowerLevel() const { return powerLevel; }

    virtual ~Fighter() {}
};

// Derived class: SaiyanWarrior
class SaiyanWarrior : public Fighter {
private:
    int superSaiyanLevel;

public:
    SaiyanWarrior(const std::string& name, int powerLevel, int ssLevel)
        : Fighter(name, powerLevel), superSaiyanLevel(ssLevel) {}

    void showInfo() const override {
        std::cout << "[Saiyan] " << name
                  << "  Power: " << powerLevel;
        if (superSaiyanLevel > 0) {
            std::cout << "  Super Saiyan Level: " << superSaiyanLevel;
        }
        std::cout << std::endl;
    }

    void transformSSJ() {
        superSaiyanLevel++;
        powerLevel *= 50;
        std::cout << name << " transformed to Super Saiyan Level "
                  << superSaiyanLevel << "! Power: " << powerLevel << std::endl;
    }

    int getSuperSaiyanLevel() const { return superSaiyanLevel; }
};

// Derived class: NamekianWarrior
class NamekianWarrior : public Fighter {
private:
    int regenerationCount;

public:
    NamekianWarrior(const std::string& name, int powerLevel)
        : Fighter(name, powerLevel), regenerationCount(0) {}

    void showInfo() const override {
        std::cout << "[Namekian] " << name
                  << "  Power: " << powerLevel
                  << "  Regenerations: " << regenerationCount << std::endl;
    }

    void regenerate() {
        regenerationCount++;
        std::cout << name << " regenerated ("
                  << regenerationCount << " times)" << std::endl;
    }
};

// Demo: nullptr
void demoNullptr() {
    std::cout << "=== nullptr Demo ===" << std::endl;

    // Initialize with nullptr (represents uninitialized pointer state)
    Fighter* goku   = nullptr;
    Fighter* vegeta = nullptr;

    if (goku == nullptr) {
        std::cout << "Son Goku has not appeared yet (nullptr)" << std::endl;
    }

    goku   = new SaiyanWarrior("Son Goku",  90000, 0);
    vegeta = new SaiyanWarrior("Vegeta", 18000, 0);

    goku->showInfo();
    vegeta->showInfo();

    delete goku;
    delete vegeta;
    goku   = nullptr;
    vegeta = nullptr;

    std::cout << std::endl;
}

// Demo: static_cast
void demoStaticCast() {
    std::cout << "=== static_cast Demo ===" << std::endl;

    double freezaPowerDouble = 530000.75;
    int freezaPowerInt = static_cast<int>(freezaPowerDouble);
    std::cout << "Frieza power (double): " << freezaPowerDouble << std::endl;
    std::cout << "Frieza power (int):    " << freezaPowerInt    << std::endl;

    SaiyanWarrior* gohan = new SaiyanWarrior("Son Gohan", 200000, 2);
    Fighter* fighterPtr = static_cast<Fighter*>(gohan);
    fighterPtr->showInfo();

    SaiyanWarrior* gohanBack = static_cast<SaiyanWarrior*>(fighterPtr);
    std::cout << gohanBack->getName() << " Super Saiyan Level: "
              << gohanBack->getSuperSaiyanLevel() << std::endl;

    delete gohan;
    std::cout << std::endl;
}

// Demo: dynamic_cast
void demoDynamicCast() {
    std::cout << "=== dynamic_cast Demo ===" << std::endl;

    std::vector<Fighter*> fighters;
    fighters.push_back(new SaiyanWarrior("Son Goku",  3000000, 3));
    fighters.push_back(new NamekianWarrior("Piccolo", 800000));
    fighters.push_back(new SaiyanWarrior("Vegeta", 2500000, 2));

    for (int i = 0; i < (int)fighters.size(); i++) {
        fighters[i]->showInfo();

        SaiyanWarrior* saiyajin = dynamic_cast<SaiyanWarrior*>(fighters[i]);
        if (saiyajin != nullptr) {
            saiyajin->transformSSJ();
        }

        NamekianWarrior* namekian = dynamic_cast<NamekianWarrior*>(fighters[i]);
        if (namekian != nullptr) {
            namekian->regenerate();
        }
    }

    for (int i = 0; i < (int)fighters.size(); i++) {
        delete fighters[i];
        fighters[i] = nullptr;
    }

    std::cout << std::endl;
}

// Demo: reinterpret_cast
void demoReinterpretCast() {
    std::cout << "=== reinterpret_cast Demo ===" << std::endl;

    SaiyanWarrior trunks("Trunks", 5000000, 2);
    uintptr_t address = reinterpret_cast<uintptr_t>(&trunks);
    std::cout << "Trunks memory address (decimal): " << address << std::endl;

    SaiyanWarrior* trunksPtr = reinterpret_cast<SaiyanWarrior*>(address);
    std::cout << "Name retrieved from restored pointer: " << trunksPtr->getName() << std::endl;

    std::cout << std::endl;
}

int main() {
    demoNullptr();
    demoStaticCast();
    demoDynamicCast();
    demoReinterpretCast();
    return 0;
}
g++ -std=c++11 dragon_ball_cast.cpp -o dragon_ball_cast
./dragon_ball_cast
=== nullptr Demo ===
Son Goku has not appeared yet (nullptr)
[Saiyan] Son Goku  Power: 90000
[Saiyan] Vegeta  Power: 18000

=== static_cast Demo ===
Frieza power (double): 530000.75
Frieza power (int):    530000
[Saiyan] Son Gohan  Power: 200000  Super Saiyan Level: 2
Son Gohan Super Saiyan Level: 2

=== dynamic_cast Demo ===
[Saiyan] Son Goku  Power: 3000000  Super Saiyan Level: 3
Son Goku transformed to Super Saiyan Level 4! Power: 150000000
[Namekian] Piccolo  Power: 800000  Regenerations: 0
Piccolo regenerated (1 times)
[Saiyan] Vegeta  Power: 2500000  Super Saiyan Level: 2
Vegeta transformed to Super Saiyan Level 3! Power: 125000000

=== reinterpret_cast Demo ===
Trunks memory address (decimal): 140732091613664
Name retrieved from restored pointer: Trunks

Common mistake 1: Passing NULL to an overloaded function and getting the integer version

NULL is actually integer 0, so when passed to a function with both pointer and integer overloads, the integer version may be called. Using nullptr avoids this since it is of type nullptr_t.

// NG: NULL may select the integer overload
void process(int val)    { std::cout << "Integer version: " << val << std::endl; }
void process(Fighter* p) { std::cout << "Pointer version" << std::endl; }

process(NULL);     // Integer version is called

OK: Using nullptr correctly selects the pointer version.

// OK: nullptr selects the pointer version
process(nullptr);  // Pointer version is called

Common mistake 2: Using static_cast for a downcast without verifying the actual type

static_cast does not perform a runtime type check for downcasts. Casting to an incorrect derived type results in undefined behavior. When the type is uncertain, use dynamic_cast with a nullptr check.

// NG: static_cast with incorrect actual type causes undefined behavior
Fighter* krillin = new NamekianWarrior("Krillin", 75000);
SaiyanWarrior* wrongCast = static_cast<SaiyanWarrior*>(krillin);  // Undefined behavior

OK: Use dynamic_cast for safe type checking.

// OK: Use dynamic_cast with nullptr check
SaiyanWarrior* saiyajin = dynamic_cast<SaiyanWarrior*>(krillin);
if (saiyajin != nullptr) {
    saiyajin->transformSSJ();
} else {
    std::cout << "Not a Saiyan" << std::endl;
}

Overview

nullptr is the null pointer constant introduced in C++11, replacing integer 0 and the NULL macro. Since nullptr is of type nullptr_t, it can represent an uninitialized pointer state without integer confusion, and overload resolution will not accidentally select an integer function. Using the appropriate cast operator for each purpose is important. static_cast is for compile-time conversions (numeric types, upcasts, downcasts where the type is certain); dynamic_cast is for safe downcasting of polymorphic types with runtime type checking; reinterpret_cast is for forced bit-level reinterpretation and should be limited to low-level programming. const_cast specializes in adding/removing const qualifiers — the other three casts cannot modify const. Using C-style casts like (type)expr can silently combine multiple casts and obscure intent; using C++ named casts makes the intent explicit and improves code review and debugging.

If you find any errors or copyright issues, please .