Casting is one of the most troublesome operations in C/C++ as when you use casts you are directing the compiler to trust you and to forget about type checking. Casts should be used as infrequently as possible and only when there is no alternative. We have two main terms for casting, upcasting and downcasting. Upcasting is casting from a derived class to one of its base classes and downcasting is casting from a base class to one of its derived classes. Remember that the inheritance tree branches down with the base class at the top. We also have the lesser known cross-casting for casting a class to a sibling class.
C++ introduces new explicit casts that identify the rationale behind the cast, clearly identifies that a cast is taking place and confirms type-safe conversions. These casts are:
static_cast for well-behaved casts such as automatic conversions, narrowing
conversions (e.g. a float to int), a conversion from void*, and
safe downcasts (moving down the inheritance hierarchy) for non-polymorphic classes. If the base class is a virtual
base class then you must use a dynamic_cast
dynamic_cast is used for type-safe downcasting. The format of a dynamic cast is
dynamic_cast <type>(expression) and requires that the expression is a pointer if the type
is a pointer type. If a dynamic_cast fails then a null pointer is returned.
The dynamic_cast is actually safer than the static_cast as it performs
a run-time check, to check for ambigious casts (in the case of multiple-inheritance).
const_cast is used for casting away const or volatile.
reinterpret_cast is the most dangerous cast. It allows us to convert an object into any
other object for the purpose of modifying that object - often for low-level "bit-twiddling" as it is known.
Here is an example of all four casts:
1
2 // Start reading from main() function to help make it easier to understand
3 #include <iostream>
4 using namespace std;
5
6 // Demo classes with a virtual base class
7 class Account {
8 public:
9 float balance; // for demonstration only!
10 virtual ~Account(){}
11 };
12 class Current: public Account {};
13 class Test { public: float x, y;};
14
15 // Demo Function
16 void someFunction(int& c)
17 {
18 c++; // c can be modified
19 cout << "c has value " << c << endl; //will output 11
20 }
21
22 int main()
23 {
24 float f = 200.6f;
25 // narrowing conversion, but we have notified the compiler
26 int x = static_cast<int>(f);
27 cout << x << endl;
28
29 Account *a = new Current; //upcast - cast derived to base
30 //type-safe downcast - cast base to derived
31 Current *c = dynamic_cast<Current*>(a);
32
33 const int i = 10; // note i is const
34 //someFunction(i); // is an error as someFunction
35 // could modify the value of i
36 someFunction(*const_cast<int*>(&i));
37 // Allow i be passed to the function but it will still remain at 10.
38 cout << "i has value " << i << endl; // will still output 10
39
40 a = new Account;
41 a->balance = 1000;
42 //convert account address to long
43 long addr = reinterpret_cast<long>(a);
44
45 // safe to convert long address into an Account
46 Account* b = reinterpret_cast<Account*>(addr);
47 cout << "The balance of b is " << b->balance << endl;
48
49 // could convert to any class regardless of
50 // inheritance - ok this time! (not safe)
51 Current* cur = reinterpret_cast<Current*>(addr);
52 cout << "The balance of cur is " << cur->balance << endl;
53
54 // works, but not definitely not safe this time!
55 Test* test = reinterpret_cast<Test*>(addr);
56 cout << "The value of the float x is " << test->x <<
57 " and float y is " << test->y << endl;
58 }
59
The output of this code is:
C:\My Documents\My Teaching\OOP Notes\EE553_Output\cpp>casting 200c has value 11 i has value 10
The balance of b is 1000
The balance of cur is 1000
The value of the float x is 1000 and float y is 5.98875e-39
![]()
© 2006
Dr. Derek Molloy
(DCU).