In lesson 10.1 -- Implicit type conversion, we discussed that the compiler can use implicit type conversion to convert a value from one data type to another. When you want to numerically promote a value from one data type to a wider data type, using implicit type conversion is fine.
Many new C++ programmers try something like this:
double d = 10 / 4; // does integer division, initializes d with value 2.0
Because 10 and 4 are both of type int, integer division is performed, and the expression evaluates to int value 2. This value then undergoes numeric conversion to double value 2.0 before being used to initialize variable d. Most likely, this isn’t what was intended.
In the case where you are using literal operands, replacing one or both of the integer literals with double literals will cause floating point division to happen instead:
double d = 10.0 / 4.0; // does floating point division, initializes d with value 2.5
But what if you are using variables instead of literals? Consider this case:
int x { 10 };
int y { 4 };
double d = x / y; // does integer division, initializes d with value 2.0
Because integer division is used here, variable d will end up with the value of 2.0. How do we tell the compiler that we want to use floating point division instead of integer division in this case? Literal suffixes can’t be used with variables. We need some way to convert one (or both) of the variable operands to a floating point type, so that floating point division will be used instead.
Fortunately, C++ comes with a number of different type casting operators (more commonly called casts) that can be used by the programmer to have the compiler perform type conversion. Because casts are explicit requests by the programmer, this form of type conversion is often called an explicit type conversion (as opposed to implicit type conversion, where the compiler performs a type conversion automatically).
Type casting
C++ supports 5 different types of casts: static_cast, dynamic_cast, const_cast, reinterpret_cast, and C-style casts. The first four are sometimes referred to as named casts.
For advanced readers
| Cast | Description | Safe? |
|---|---|---|
| static_cast | Performs compile-time type conversions between related types. | Yes |
| dynamic_cast | Performs runtime type conversions on pointers or references in an polymorphic (inheritance) hierarchy | Yes |
| const_cast | Adds or removes const. | Only for adding const |
| reinterpret_cast | Reinterprets the bit-level representation of one type as if it were another type | No |
| C-style casts | Performs some combination of static_cast, const_cast, or reinterpret_cast. |
No |
Each cast works the same way. As input, the cast takes an expression (that evaluates to a value or an object), and a target type. As output, the cast returns the result of the conversion.
Because they are the most commonly used casts, we’ll cover C-style casts and static_cast in this lesson.
Related content
We discuss dynamic_cast in lesson 25.10 -- Dynamic casting, after we’ve covered other prerequisite topics.
const_cast and reinterpret_cast should generally be avoided because they are only useful in rare cases and can be harmful if used incorrectly.
Warning
Avoid const_cast and reinterpret_cast unless you have a very good reason to use them.
C-style cast
In standard C programming, casting is done via operator(), with the name of the type to convert to placed inside the parentheses, and the value to convert to placed immediately to the right of the closing parenthesis. In C++, this type of cast is called a C-style cast. You may still see these used in code that has been converted from C.
For example:
#include <iostream>
int main()
{
int x { 10 };
int y { 4 };
std::cout << (double)x / y << '\n'; // C-style cast of x to double
return 0;
}
In the above program, we use a C-style cast to tell the compiler to convert x to a double. Because the left operand of operator/ now evaluates to a floating point value, the right operand will be converted to a floating point value as well, and the division will be done using floating point division instead of integer division.
C++ also provides an alternative form of C-style cast known as a function-style cast, which resembles a function call:
std::cout << double(x) / y << '\n'; // // function-style cast of x to double
The function-style cast makes it a bit easier to tell what is being converted (as it looks like a standard function argument).
There are a couple of significant reasons that C-style casts are generally avoided in modern C++.
First, although a C-style cast appears to be a single cast, it can actually perform a variety of different conversions depending on how it is used. This can include a static cast, a const cast, or a reinterpret cast (the latter two of which we mentioned above you should avoid). A C-style cast does not make it clear which cast(s) will actual be performed, which not only makes your code that much harder to understand, but also opens the door for inadvertent misuse (where you think you’re implementing a simple cast and you end up doing something dangerous instead). Often this will end up producing an error that isn’t discovered until runtime.
Also, because C-style casts are just a type name, parenthesis, and variable or value, they are both difficult to identify (making your code harder to read) and even more difficult to search for.
In contrast, the named casts are easy to spot and search for, make it clear what they are doing, are limited in their abilities, and will produce a compilation error if you try to misuse them.
Best practice
Avoid using C-style casts.
For advanced readers
A C-style cast tries to perform the following C++ casts, in order:
const_caststatic_caststatic_cast, followed byconst_cast
