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;

   cout<<d;
   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;
   cout<<"Enjoy!!";
   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!!

6 comments:

  1. Very easy and fun to reading, from my point of view the difference between static_cast and dynamic_cast was confusing util i read your blog

    ReplyDelete
  2. Greap post! One thing that you could mention is that the C++ standard defines the C-style cast in terms of combinations of C++ casts. Here's an excerpt from section 5.4.4:

    "The conversions performed by
    — a const_cast,
    — a static_cast,
    — a static_cast followed by a const_cast,
    — a reinterpret_cast, or
    — a reinterpret_cast followed by a const_cast,
    can be performed using the cast notation of explicit type conversion."

    In other words, the compiler will try and pick one of the above sequences of casts, to carry out the C-style cast. If you make a mistake with a C-style cast, and the compiler manages to find a combination of casts that works, there will be no compile error. By using explicit C++ casts, you can strictly enforce what you need.

    In addition, dynamic_cast is never used in C-style casts, so that's another danger.

    ReplyDelete
  3. Article was nice but in const_cast i dint understand,const_cast means we can change the value of const variable ex: suppose we have const int a=10
    by using const cast we can increment or decrement the value what u did i did not understand

    ReplyDelete
    Replies
    1. Casting do not effect variable you are casting on. It just change expression's type. Say you have constant variable, you cannot assign address of const variable to non const pointer, so here you use const cast, type of actual variable is not changed, but it can be assigned to const pointer.

      Delete