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
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:
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 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;
😀
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<
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'
- It’s also used to downcast a pointer to a base class
to a pointer to a derived class, without type checking.
- It’s also used to convert void * to/from any other pointer type.
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<
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;
140724487872416
-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 (e.g., stoi() or to_string()) 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