Skip to content
Theory · Casts and Aliases · lesson 3 of 6

const_cast, reinterpret_cast, using and typedef

static_cast changes the type of a value, but it cannot remove const from a pointer:

C++
int main() {
    const int limit = 10;
    int* p = static_cast<int*>(&limit);  // ✗
    return *p;
}
TEXT
error: static_cast from 'const int *' to 'int *' is not allowed

Other named casts remove const and reinterpret pointers, and each of them does one job.

const_cast

const_cast removes const from a pointer or a reference and changes nothing else: const_cast<int*>(&limit) is an int* to the same limit. It does not change the type of a value, so const_cast<int>(2.5) does not compile. It is used when a function takes an int* but only reads the value:

C++
#include <iostream>

void print_value(int* p) {
    std::cout << *p << '\n';
}

int main() {
    const int limit = 10;
    print_value(const_cast<int*>(&limit));  // 10
}

Without const_cast, such a function cannot get a const variable's address: the compiler does not turn const int* into int* itself.

reinterpret_cast and void*

With pointers, reinterpret_cast gives a pointer to another type at the same address. The bytes in memory stay the same; only the type they are read as changes. Reading a float through an int* is undefined behavior, so a beginner almost never needs this cast. It does not convert numbers: reinterpret_cast<int>(2.5) does not compile.

Some pointers change type without any cast. An int* converts implicitly to void*, a pointer to a value of unknown type, and static_cast<int*> turns it back. The fourth named cast, dynamic_cast, works only with pointers and references to classes.

Type aliases

A type alias is a second name for an existing type. It is introduced with using: using Score = long long;. The older notation for the same thing is typedef long long Score;. There the new name comes last, while using puts it on the left, as in an assignment.

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

using Score = long long;
typedef std::vector<Score> ScoreList;

int main() {
    ScoreList scores{1500000000, 1500000000};
    Score total = scores[0] + scores[1];
    std::cout << total << '\n';  // 3000000000
}

An alias does not create a new type: to the compiler, Score is long long, and ScoreList is std::vector<long long>. If Celsius and Fahrenheit are both aliases of double, a function with a Celsius parameter silently accepts a Fahrenheit. An alias makes code clearer, and the type for the whole program changes in one line. Unlike #define, an alias obeys scope: declared inside a function, it is visible only there.

Common mistake

const_cast is used to write to a variable declared const:

C++
int main() {
    const int limit = 10;
    int* p = const_cast<int*>(&limit);
    *p = 20;  // ✗
    return limit;
}

The compiler builds the program with no errors or warnings. But limit is declared const, and writing to it through p is undefined behavior: the standard does not say what main returns. Write through const_cast only to a variable declared without const. If the value has to change, remove const from the declaration.