CS253: Software Development with C++

Fall 2020

Casting

Show Lecture.Casting as a slide show.

CS253 Casting

Caution

Overview

C-style casting

In C, casting worked like this:

float f = 3.14;
unsigned int *p = &f;
printf("%#08x", *p);
c.c: In function 'main':
c.c:2: warning: initialization of 'unsigned int *' from incompatible pointer type 'float *'
0x4048f5c3
float f = 3.14;
unsigned int *p = (unsigned int *) &f;
printf("%#08x", *p);
0x4048f5c3

This works in C++, but don’t. Detect with g++ -Wold-style-cast.

Constructor “casting”

This isn’t really casting, but sure is similar:

int n;
n = int(3.14);
cout << "n is " << n << '\n';
n is 3

Of course, an actual programmer would just do this, even though a fussy compiler might issue a warning:

int n = 3.14;
cout << "n is " << n << '\n';
n is 3

With absolute power comes bad code

The problem with C-style casting is that it’s too powerful. It’s an “anything goes” sort of operation:

long l = (long) "Krypto the Superdog";
cout << l << '\n';
4196616

That’s the address of the string (array of const char) as a decimal number, a thing of questionable value. Hope it fits into a long!

C++ casting

C++ breaks up the vast power of the C-style cast into separate tools:

const_cast

char *p = "😦";
cout << p;
c.cc:1: warning: ISO C++ forbids converting a string constant to 'char*'
😦

That failed, because p is type char *, whereas "☹" is type const char[] or const char *.

const_cast

const_cast<type>(value) removes constness. You have to specify the new type, but it must be the original type with const removed.

char *p = const_cast<char *>("😀");
cout << p;
😀

const_cast

However, const_cast can only change constness, not type:

const double *p = const_cast<const double *>("😕");
cout << p;
c.cc:1: error: invalid const_cast from type 'const char*' to type 'const 
   double*'

This way, if you see const_cast, you know that it’s only removing constness.

static_cast

static_cast<type>(value): usual conversions

double d = 3.15;
int i = static_cast<int>(d);
cout << i;
3
int i = static_cast<int>("123");
cout << i;
c.cc:1: error: invalid static_cast from type 'const char [4]' to type 'int'

dynamic_cast

dynamic_cast<type>(value): Convert a pointer to a base class to a pointer to a derived class, much like static_cast, but this does type checking for polymorphic types containing virtual methods.

class Base {
  public:
    virtual void foo() { }
};
class Derived : public Base { };

Base b, *bp = &b;
Derived *dp = dynamic_cast<Derived *>(bp);
if (dp == nullptr)
    cout << "Conversion failed.\n";
else
    cout << "Conversion succeeded.\n";
Conversion failed.

reinterpret_cast

reinterpret_cast<type>(value): go nuts

double avo = 6.022e23;

long l = reinterpret_cast<long>(&avo);
cout << l << endl;

int n = *reinterpret_cast<int *>(&avo);
cout << n << endl;

int *p = reinterpret_cast<int *>(42);
cout << "Wait for it: " << flush;
cout << *p;
140727839255360
-195565037
Wait for it: SIGSEGV: Segmentation fault

When casting is not appropriate.

string s = "3.14159265";
cout << (double) s << '\n';
c.cc:2: error: invalid cast from type 'std::__cxx11::string' {aka 
   'std::__cxx11::basic_string<char>'} to type 'double'

string t = "3.14159265";
cout << stod(t) << '\n';
3.14159

string u = "42";
cout << stoi(u) << '\n';
cout << stoi(u, nullptr, 16) << '\n';
42
66