We've previously seen how our data types can be converted to other types automatically. For example, we can use an int
in a location where a float
is expected, and our int
is just automatically converted to the equivalent float:
float MyNumber { 4 };
These are called implicit conversions. They happen automatically, without us needing to write any additional code.
We also have the option, and sometimes the need, to perform explicit conversions. Explicitly converting data to another type is referred to as casting.
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.0f);
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 used when working with pointers. We'll see that in more detail later in this chapter when we cover run-time polymorphism.
static_cast
After running the following code, what is the returned by the highlighted line?
bool IsDouble(double Number) { return true; }
bool IsDouble(int Number) { return false; }
IsDouble(static_cast<int>(5.0));
Another style of casting that is sometimes used is C-style casting. It has a slightly simpler syntax but, for reasons we’ll cover later in this section, we should avoid using it.
If we had the following static_cast
code:
static_cast<int>(5.0);
static_cast<bool>(SomeVariable);
static_cast<Character>(SomeFunction());
Using C-style casting, it would look like this:
(int)5.0;
(bool)SomeVariable;
(Character)SomeFunction();
After running the following code, what is returned by the highlighted line?
bool IsDouble(double Number) { return true; }
bool IsDouble(int Number) { return false; }
IsDouble((int)5.0);
C style casting was, predictably, inherited from the C language.
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 names like static_cast
, dynamic_cast
, and reinterpret_cast
These modern operators, sometimes called named casts, should be preferred over c-style casts. They clarify exactly what we’re doing, and they perform additional checks to ensure what we’re doing makes sense for that use case.
For example, if we attempt to cast the literal "Hi"
to a number, static_cast
alerts us that this doesn’t make sense when we try to compile our code:
#include <iostream>
using namespace std;
int main(){
cout << static_cast<int>("Hi");
}
error: 'static_cast': cannot convert from
'const char [3]' to 'int'
There is no context in which this conversion
is possible
The equivalent C-style cast performs no such checks - it lets our program compile, and leaves us with unpredictable behavior:
#include <iostream>
using namespace std;
int main(){
cout << (int)"Hi";
}
2041494544
In this lesson, we covered:
static_cast<SomeType>(SomeExpression)
is used for converting one data type to another, and it can be applied to literals, variables, function calls, and more.The next lesson will delve into run-time polymorphism, using virtual functions and overrides. We’ll cover:
override
keyword, and how overrides enable polymorphic behavior, allowing derived classes to provide specific implementations for virtual functions.final
keyword.Explore the concept of static casting in C++, including examples and best practices for converting data types at compile time
Become a software engineer with C++. Starting from the basics, we guide you step by step along the way