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:
cout << (long) "Krypto the Superdog"; // 🦡
4196344
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:
When you see one of the C++ casts, you and the compiler know what the
programmer was trying to do.
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 *. You can’t assign a
const char * address to a char * pointer, because that would result in
read/write access to a read-only location. That’s upgrading your access,
which is not something to be done casually.
Downgrading your access is fine, however. You can assign a
char * address to a const char * pointer, because that results in a
pointer with less power. Even though I own a book, and have the legal
write to destroy it, I can choose not to.
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*’
If you see const_cast, you know that it’s only removing constness,
not sneakily changing types on you.
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 *>(17);
cout << "Wait for it: " << flush;
cout << *p; // 🦡
140728906440528
-195565037
Wait for it: SIGSEGV: Segmentation fault
When casting is not appropriate.
- Don’t think that casting and “conversion” are the same thing.
- Casting won’t convert a digit string to or from 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::string’ {aka
‘std::__cxx11::basic_string<char>’} to type ‘double’
string t = "3.14159265";
cout << stod(t)*2 << '\n';
6.28319
string u = " +042";
cout << stoi(u) << '\n'
<< stoi(u, nullptr, 16) << '\n';
42
66
string v = "CS" + to_string(253);
cout << v << '\n';
CS253