Show Lecture.Casting as a slide show.
CS253 Casting
Caution
- Casting is generally a mistake.
- If you find yourself doing it, you probably screwed up.
- Reconsider your actions.
- Sometimes, you have to do it.
Overview
- C-style casting:
(
type)
value
- Constructor “casting”: type
(
value)
const_cast<
type>(
value)
static_cast<
type>(
value)
dynamic_cast<
type>(
value)
reinterpret_cast<
type>(
value)
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 *'
4048f5c3
float f = 3.14;
unsigned int *p = (unsigned int *) &f;
printf("%08x", *p);
4048f5c3
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<
type>(
value)
: remove const
ness
static_cast<
type>(
value)
: usual conversions
dynamic_cast<
type>(
value)
: object type conversion
reinterpret_cast<
type>(
value)
: go nuts
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<
type>(
value)
removes const
ness.
You have to specify the new type, but it must be the original
type with const
removed.
char *p = const_cast<char *>("😀");
cout << p;
😀
However, const_cast
can only change const
ness, 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 const
ness.
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<
type>(
value)
:
Convert a pointer to a base class to a pointer to a derived class.
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<
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;
140727958742096
-195565037
Wait for it: SIGSEGV: Segmentation fault
When casting is not appropriate.
- Don’t think that casting and “conversion” are the same thing.
- No form of casting will convert a
string
containing digits
to an int
.
- Other functions are required.
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