Wednesday, July 6, 2011

C++ Type Casting

C++ Typecasting

If you all are lover of C style casting, then it is time to change you mood. C++ also provides four new casts: static_cast, dynamic_cast, const_cast, and reinterpret_cast. You should use the C++ style casts instead of the old C-style casts because they perform more type checking and stand out better syntactically in your code. This section describes the purposes for each cast and specifies when you would use each of them.



static_cast

You can use the static_cast to perform explicitly conversions that are supported directly by the language. For example, if you write an arithmetic expression in which you need to convert an int to a double in order to avoid integer division, use a static_cast:

int i = 3;
double result = static_cast<double>(i) / 10;

You can also use static_cast to perform explicitly conversions that are allowed because of userdefined constructors or conversion routines. For example, if class A has a constructor that takes an object of class B, you can convert a B object to an A object with a static_cast. In most situations where you want this behavior, however, the compiler will perform the conversion automatically. Another use for the static_cast is to perform downcasts in an inheritance hierarchy. For example:

class CBase {
public:
CBase() {};
virtual ~CBase() {}
};

class CDerived : public CBase {
public:
CDerived() {}
virtual ~Derived() {}
};

int main(int argc, char** argv){
CBase* b;
CDerived* d = new Derived();
b = d; // Don’t need a cast to go up the inheritance hierarchy
d = static_cast<Derived*>(b); // Need a cast to go down the hierarchy
CBase base;
CDerived derived;
CBase& br = base;
CDerived& dr = static_cast<CDerived&>(br);
return 0;
}

These casts work with both pointers and references. They do not work with objects themselves.

Note that these casts with static_cast do not perform runtime type checking. They allow you to convert any Base pointer to a Derived pointer or Base reference to a Derived reference, even if the Base really isn’t a Derived at run time. To perform the cast safely, with runtime type checking, use the dynamic_cast.
static_cast are not all-powerful. You can’t static_cast pointers of one type to pointers of another unrelated type. You can’t static_cast pointers to ints. You can’t static_cast directly objects of one type to objects of another type. You can’t static_cast a const type to a non-const type. Basically, you can’t do anything that doesn’t make sense according to the type rules of C++.

reinterpret_cast

The reinterpret_cast is a bit more powerful, and concomitantly less safe, than the static_cast.
You can use it to perform some casts that are not technically allowed by C++ type rules, but which might make sense to the programmer in some circumstances. For example, you can cast a pointer type to any other pointer type, even if they are unrelated by an inheritance hierarchy. Similarly, you can cast a reference to one type to a reference to another type, even if the types are unrelated. You can also cast pointers to ints and ints to pointers. Here are some examples:

class X {};
class Y {};

int main(int argc, char** argv) {
int i = 3;
X x;
Y y;
X* xp;
Y* yp;

// reinterpret cast to perform pointer conversion from unrelated classes
// static_cast doesn’t work.
xp = reinterpret_cast<X*>(yp);
// Need reinterpret_cast to go from pointer to int and from int to pointer
i = reinterpret_cast<int>(xp);
xp = reinterpret_cast<X*>(i);
// reinterpret cast to perform reference conversion from unrelated classes
// static_cast doesn’t work.

X& xr = x;
Y& yr = reinterpret_cast<Y&>(x);
return 0;
}

You should be very careful with the reinterpret_cast because it “reinterprets” raw bits as a different
type without performing any type checking.

dynamic_cast

As mentioned in the discussion of static_cast, the dynamic_cast provides a run-time check on casts within an inheritance hierarchy. You can use it to cast pointers or references. dynamic_cast checks the runtime type information of the underlying object at run time. If the cast doesn’t make sense, dynamic_cast returns NULL (for the pointer version) or throws a bad_cast exception (for the reference version).

Note that the runtime-type information is stored in the vtable of the object. Therefore, in order to use dynamic_cast, your classes must have at least one virtual function. Here are some examples:

#include <iostream>

using namespace std;

class CBase {
public:
CBase() {};
virtual ~CBase() {}
};
class CDerived : public CBase
{
public:
CDerived() {}
virtual ~CDerived() {}
};
int main(int argc, char** argv)
{
CBase* b;
CDerived* d = new CDerived();
b = d;
d = dynamic_cast<CDerived*>(b);
CBase base;
CDerived derived;
CBase& br = base;
try {
CDerived& dr = dynamic_cast<CDerived&>(br);
}
catch (bad_cast&) {
cout << “Bad cast!\n”;
}
return 0;
}

In the preceding example, the first cast should succeed, while the second should throw an exception. Chapter 15 covers the details of exception handling. Note that you can perform the same casts down the inheritance hierarchy with a static_cast or reinterpret_cast. The difference with dynamic_cast is that it performs runtime (dynamic) type
checking.

Summary of Casts

The following table summarizes the casts you should use for difference situations.


1 comment: