Saturday, August 24, 2013

C++ style casts

C++ Style Casts

C style casting can be abused in many ways. First without much effort one can change type of variable or expression, secondly it is hard to identify where type casting is used, because you just need parenthesis and identifier to do type casting. It is difficult to distinguish normal expression and type casting in C source code, so text finding tools will also be of little help.
C style cast cannot be completely blamed because it was good with C code; C++ has inheritance and polymorphism, which were foreign concepts for C, so there was no reason for C to distinguish between upcasting and downcasting.  
To overcome these issues C++ came up with four new casting keywords viz., static_cast,   dynamic_cast, const_cast, reinterpret_cast.

1.     static_cast

This is general purpose cast, and generally used for casting like from int to double. So whenever you want to typecast, you most of time end up using static_cast. Let’s take following expression,
double b = (double)10/20; /*C style cast from int to double */
double b = static_cast<double> (10) /20; // C++ style cast
Looks clumsy! Yes it is. This is blessing in disguised. It is not easy to read and write syntax, and so you can easily distinguish type casting from other code, secondly all static_cast can be easily found using ‘text search’ tools.
See following code to understand how to use static_cast in C++ program.
#include "stdafx.h"
#include <iostream>
using namespace std;

int main(int argccharargv[])
   int a = 10;
   int b = 20;

   double d = static_cast<double>(a)/b;

   return 0;
Output: 0.5

2.     const_cast

Consider following code snippet
const int a = 10;
int *b = static_cast<int*>(&a); //error static_cast cannot takeaway constness
Problem with above code you are trying to take away const-ness using static_cast and C++ won’t allow this. For this there is special keyword and that is const_cast. Rewritting above code as,
const int a = 10;
int *b = const_cast<int*>(&a);//works fine
Compiler will accept this happily. So, if you want to take away const or volatile use const_cast and not any other cast.
So there is one more advantage of using C++ style cast, that you need to consciously decide and specify what you intent to do. In C there is no such distinction.

3.     dynamic_cast

Upcasting in is perfectly acceptable, since it is casting to generalized type in hierarchy. While doing downcasting may not be always correct. dynamic_cast prevents form incorrect downcasting. If casting is valid result of dynamic cast is valid pointer, otherwise it returns null. Consider following code,
#include <iostream>
using namespace std;

class shape{public :virtual ~shape(){}};
class circle:public shape{};
class square:public shape{};

int main(int argccharargv[])
   shape *b = new circle//Upcasting
   square* s = dynamic_cast<square*> (b);//downcasting to incorrect type
   (s!=NULL)?cout<<"Right cast"<<endl:cout<<"Wrong cast"<<endl;
    circle *c = dynamic_cast<circle*> (b);//downcasting to correct type
   (c!=NULL)?cout<<"Right cast"<<endl:cout<<"Wrong cast"<<endl;

   return 0;
Output : Wrong Cast
             Right Cast
In program, first we have upcasted circle pointer to shape which is perfectly acceptable, then we are trying to downcast upcasted circle pointer to square pointer using dynamic_cast which is not acceptable as it is incorrect conversion. Finally we downcast upcasted circle pointer to circle pointer using dynamic_cast, which is perfectly acceptable.
Remember, with old style cast both the casting (from circle to circle and from square to circle) is permissible, and program is leaved to its fate.

4.     reinterpret_cast

This is unsafe. It can convert int to pointer and any class pointer to any class pointer. Hope you understand ;). When you convert from any unrelated type to any unrelated type, no one guarantees expected output. Unpredictable behavior. For sake of completeness of article, with advice of not to use it, see following example of reinterpret_cast.
#include <iostream>
using namespace std;

int main(int argccharargv[])
   int a = 0x1233254;
   char *ptr = reinterpret_cast<char*> (a);
   *ptr = 3;
   return 0;
So, we have covered all types of C++ style cast.
Please add comments below, about your suggestions and views on this.
Happy programming!!