static_cast
We've previously seen how our data types can be converted to other types implicitly. For example, we could convert an int
to a float
by simply creating a variable of type float
from it:
float MyNumber { 4 };
We're now starting to see scenarios where this form of conversion has its limitations:
void OverloadedFunction(int Value) {}
void OverloadedFunction(float Value) {}
// Ambiguous - should I convert the double to an int or to a float?
OverloadedFunction(5.0);
We could, of course, create another variable to do this conversion for us. But there's a better way, which is called Casting.
Casting is a way that we can explicitly instruct our code to carry out conversions. It will let us solve this current problem directly, without adding extra variables.
It also lays the groundwork for more powerful forms of conversion that we will see in the next chapter.
static_cast
C++ offers many different styles of casting. The two most interesting types are static casting which is done at build time, and dynamic casting which is done at run time. We'll look at dynamic casting later in the course.
Because static casting lets us convert our data at build time, this means it has two useful properties:
To convert the integer 5
to a float
, we can do this:
static_cast<float>(5)
To convert the double 5.0
to an int
, we can do this:
static_cast<int>(5.0)
More generally, if we want to convert SomeExpression
into anSomeType
, the pattern looks like this:
static_cast<SomeType>(SomeExpression)
SomeExpression
is anything that contains or returns data of type SomeType
, or data that can be converted into data of SomeType
.
The expression can be a literal value, as shown above; it might be a variable, it might be a call to a function; it might be a maths operation, and so on.
Here are some examples:
static_cast<int>(20.f);
static_cast<int>(25.0);
static_cast<int>(25.0 / 5);
float SomeFloat { 10.f };
static_cast<int>(SomeFloat);
bool SomeBoolean { true };
static_cast<int>(SomeBoolean ? 20 : 50.0 );
double SomeFunction() { return 1.0; }
static_cast<int>(SomeFunction());
Equally, the thing that is returned from a call to static_cast<int>
is an integer, and can be used anywhere that an integer is valid:
// Saving the result to a variable
int MyInt1 { static_cast<int>(20.f) };
int MyInt2 { static_cast<int>(25.0) / 5 };
int Add(int x, int y) { return x + y; }
// Passing the result to a function
Add(
static_cast<int>(1.f),
static_cast<int>(2.0)
);
These examples are heavily focused on using static_cast
to convert to an int
, but it can be used on any data type.
static_cast<float>(5.0);
static_cast<bool>(142);
static_cast<double>(5);
Static casting can also be useful when working with our own custom data types, like Character
, but we'll see that in more detail in the later lessons that cover polymorphism.
After running the following code, what is the value of MyBool
?
bool GetBool(float Number) { return true; }
bool GetBool(int Number) { return false; }
bool MyBool { GetBool(static_cast<int>(5.0)) };
Another style of casting that is sometimes used is called C-style casting. It has a slightly simpler syntax.
If we had the following static_cast
code:
static_cast<int>(5.0);
Using C-style casting, it would look like this:
(int)5.0;
After running the following code, what is the value of MyBool
?
bool GetBool(float Number) { return true; }
bool GetBool(int Number) { return false; }
bool MyBool { GetBool((int)5.0) };
C style casting was, predictably, inherited from the C language. C++ introduced better forms of casting - including static_cast
. These should be used instead, with C-style casting generally being avoided.
The original C language only had one form of casting, which was used to cover all use cases. C++ has several options, covering a range of possible use cases, identified by the names like static_cast
and dynamic_cast
.
We've only included this section on C style casting because it is still used a lot. It can be be tempting to use c-style casts it instead of static_cast
. This is understandable, given that static_cast
has a slightly more complicated syntax that takes longer to type.
The "named casts" introduced in C++ give us better control over our code, they're easier to find in large code bases, and each one has further advantages when used for the specific use case it is designed for.
For example, when dealing with more complicated data types that we'll see soon, static_cast
does additional checks at compile time. This can alert us much quicker if we're trying to do a cast that is impossible.
Doing the exact same cast using a C-style cast might pass compilation and leave us with a bug.
Become a software engineer with C++. Starting from the basics, we guide you step by step along the way