Typecasting in c++ is of 4 types. This is explained below:
static_cast:
This is first and simple kind of typecasting in c++. This is used to perform all conversions that are well-defined.
Used For Conversions between built-in types: These include “safe” conversions that the compiler would allow you to do without a cast. i.e., cast from smaller built-in type to bigger built-in type, like,
- int to long
- float to double
Since, these are well defined cases, In such cases, there are no errors or warnings both with and without static_cast
int ivar;
long lvar;
lvar = ivar; //This is ok
lvar = static_cast<long>(ivar); //This is also ok
float fvar;
double dvar;
dvar = fvar;
//This is ok
dvar = static_cast<double>(fvar); //This is also ok
This is also used in Less-safe conversions that are nonetheless well defined. This cast may result in loss of data, like, cast from bigger built-in type to smaller built-in type, like,
- long to int
- double to float
int ivar;
long lvar;
ivar = lvar; //This is NOT ok
ivar = static_cast<long>(lvar); //This is also ok
float fvar;
double dvar;
fvar = dvar; //This is NOT ok
fvar = static_cast<double>(dvar); //This is also ok
The compiler generate warnings when such conversions are used without static_cast.
Used For Conversion between any pointer to void* pointer & vice versa
The first conversion type includes, safe-conversion from any pointer to void* type and second is less safe reverse conversion.
int *ivar;
void *vvar;
vvar = ivar; //This is ok
vvar = static_cast<void*>(ivar) //This is also ok
ivar = vvar; //This is NOT ok
ivar = static_cast<int*>(vvar); //This is ok
Used For Conversion during Upcasting & Downcasting in inheritance: Cast from Derived class pointer to Base class pointer when no virtual functions are present (Upcasting). This is safe operation.
Base *bptr = new Base();
Derived *dptr = new Derived();
bptr = dptr; //This is ok
bptr = static_cast<Base*>(dptr); //This is also ok
Also Downcasting, which is less safe, cast from Base class pointer to derived class pointer
#include <iostream> //main header
using namespace std; //for namespace
class MFBase
{
public:
virtual ~MFBase() {}
};
class MFDerived : public MFBase
{
public:
virtual ~MFDerived() {}
};
int main() //main function
{
MFBase *bptr = new MFBase();
MFDerived *dptr = new MFDerived();
dptr = bptr; //This is NOT ok
dptr = static_cast<MFDerived*>(bptr) //This is ok
return 0;
}
Without static_cast, the compiler may generate errors in down-cast.
const_cast
The programs uses this cast to convert from a const type to a non-const type or from a volatile to a non-volatile type
If the expression includes any other conversion then they must be done using a separate cast. Otherwise, the compilation of the code shall produce an error.
Example,
Without const_cast, error generated:
const int civar = 8;
int *ivar = &civar; //This is NOT ok
const_cast will remove the warning
int *ivar = const_cast<int*>(&civar);
Similary, const_cast will cast a type from volatile to non-volatile
volatile int vi = 8;
int *i = &vi; //This is NOT ok
Following is also example of NOT ok
volatile int *vi;
const int *ci = vi;
With const cast, there will be no error/warning in such conversions
const int *civar = const_cast<const int*>(vivar);
dynamic_cast
This is a special cast and programs use this cast for type-safe downcasting. When dynamic_cast try to cast down to a particular type, the return value will be a pointer to the desired type only.
If dynamic_cast cannot downcast an object to desired type then it returns NULL value.
The dynamic_cast is dependent on polymorphic hierarchy – one with virtual functions. This is because dynamic_cast uses information stored in the VTABLE for determining the actual type at runtime.
#include <iostream> //main header
using namespace std;//for namespace
class MFBase
{
public:
virtual ~MFBase(){}
};
class MFDerived : public MFBase
{
};
int main() //main function
{
MFBase *b1 = new MFBase;
MFDerived *d1 = dynamic_cast<MFDerived*>(b1); //Invalid
cout << d1 << endl;
MFBase *b2 = new MFDerived;
MFDerived *d2 = dynamic_cast<MFDerived*>(b2); // Valid
cout << d2 << endl;
return 0;
}
The output of dynamic_cast is:
0
0x2603c40
The dynamic_cast will work only if the class uses virtual functions. Otherwise, if there are no virtual function, the compiler will generate error:
reinterpret_cast
This is the least safe cast compared to other casts. This cast converts any type to completely different type. The reinterpret_cast assumes that an object is just a bit pattern. This cast converts by treating the bit pattern to an entirely different type of object. This method is similar to C-style casts. This is a low-level cast.
This cast can potentially produce bugs therefore, users should use this very carefully.
#include <iostream> //main header
using namespace std;//for namespace
class MFBase
{
int yvar;
public:
~MFBase(){}
};
class MFDerived : public MFBase
{
int xvar;
};
int main()
{
MFBase *bvar1 = new MFDerived;
int *ivar = reinterpret_cast<int*>(bvar1);
cout << ivar << endl;
MFBase *bvar2 = reinterpret_cast<MFBase*>(ivar);
cout << bvar2 << endl;
return 0;
}
The output is:
0xb2cc20
0xb2cc20