Static Casting

Explore the concept of static casting in C++, including examples and best practices for converting data types at compile time
This lesson is part of the course:

Intro to C++ Programming

Become a software engineer with C++. Starting from the basics, we guide you step by step along the way

Free, Unlimited Access
3D art showing a fantasy character working in an office
Ryan McCombe
Ryan McCombe
Updated

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 Casting with 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:

  • There is a minimal performance impact, and often no performance impact at all
  • The compiler can check if the cast is possible

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.

Test your Knowledge

Using 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));

C-Style Casting

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();
Test your Knowledge

Using C-Style Casts

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

Summary

In this lesson, we covered:

  • Static casting is a type of explicit conversion performed at build time, allowing for type conversion with minimal or no performance impact.
  • The syntax 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.
  • Static casting can check the conversion's validity at compile time, reducing runtime errors.
  • While static casting is commonly used for primitive types, it's also applicable to pointers and will be explored further in the context of run-time polymorphism.
  • C-style casting, inherited from C, is simpler but less safe than static casting, as it lacks compile-time checks and can lead to unpredictable behavior.

Preview: Virtual Functions and Overrides

The next lesson will delve into run-time polymorphism, using virtual functions and overrides. We’ll cover:

  • What our goals are with run time polymorphism, and the situations where it is useful
  • How to implement run-time polymorphism, by combining inheritance, references, pointers, and virtual functions.
  • An overview of early binding and late binding, and what it means in the context of class functions
  • The override keyword, and how overrides enable polymorphic behavior, allowing derived classes to provide specific implementations for virtual functions.
  • How to prevent overriding, using the final keyword.
  • Examples will demonstrate the practical application of these concepts in real-world scenarios
  • An introduction to slicing, and why it’s commonly a bug

Was this lesson useful?

Next Lesson

Virtual Functions and Overrides

This lesson provides an introduction to virtual functions and overrides, focusing on their role in enabling runtime polymorphism
3D art showing a programmer
Ryan McCombe
Ryan McCombe
Updated
Lesson Contents

Static Casting

Explore the concept of static casting in C++, including examples and best practices for converting data types at compile time

3D art showing a progammer setting up a development environment
This lesson is part of the course:

Intro to C++ Programming

Become a software engineer with C++. Starting from the basics, we guide you step by step along the way

Free, Unlimited Access
Polymorphism
3D art showing a progammer setting up a development environment
This lesson is part of the course:

Intro to C++ Programming

Become a software engineer with C++. Starting from the basics, we guide you step by step along the way

Free, unlimited access

This course includes:

  • 56 Lessons
  • Over 200 Quiz Questions
  • 95% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Next Lesson

Virtual Functions and Overrides

This lesson provides an introduction to virtual functions and overrides, focusing on their role in enabling runtime polymorphism
3D art showing a programmer
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved