In C-Style typecasting we discussed about type casting and why is it required and how it is used in C programming. C++ has more types of typecasting and an entirely different way to use them.
A point to be noted that C++ typecasting would be mostly described and used in context of classes, as an effect of C++ being object oriented.
There are following four types of type casting in C++:
Static cast is generally said to be used for non-polymorphic types. That is, the casting is done on the basis of compile time details. Static cast is done for type casting a base class to derived class and vice versa.
The Syntax:
Here is the usage source code snippet:
In the above example, we are not using any run-time polymorphism. The typecasting statement;
Here, basically we want to create an object of the derived class out of the Base class, and hence the need of the type casting. Since, we know the type of the final object to be used (i.e. the class 'Derived' in our example) at the compile time itself, therefore we use static type cast here.
However, we need to define a copy constructor to leverage the type cast, else it might not know, how and what base object data members to map to the derived object data members. If you donot specify the copy constructor and if the compiler gets confused, it might thrown an error:
The solution to the above error is defining a copy constructor.
Anyhow, although you must have guessed, here is the output of the above example:
Besides, you can use static cast to convert an enumeration to int or any expression to void in which case, the actual value is lost. But do take care, static cast is not very safe, and at times, things compile fine using any invalid type cast, and the actual problem might surface out during run time.
Dynamic cast is used for polymorphic types, that is the where types are determined at the runtime. Very apt scenarios are in inheritence where a pointers are type casted dynamically to any class in the inheritence hierarchy.
The syntax:
Dynamic type casting takes care of the cast type safety and hence, if dynamic casting fails, a NULL pointer is returned, and a valid object pointer is returned in case of success.
An example to illustrate the usage is
In this example, we are trying to typecast a Derived class pointer to Base class at runtime. By runtime, a Base class pointer is allowed to point to a Base class object as well as to a Derived class object by the compiler. Hence, it can be governed by the programmer at the runtime to change the object the pointer is pointing to.
The output being:
Please note, we've added a check after the dynamic cast on the resulting pointer 'b' if it's NULL or not. In case the dynamic cast is success, non-null desired pointer is returned. A null pointer is returned in case the dynamic cast fails. As for example, when we try to type cast a derived class pointer to a base class, which is invalid and hence results in a failure. The source code snippet is:
The const-cast is used to modify the contant-ness or volatility of any expression. It does not affect the data type of the variable or expression.
The Syntax:
An example:
The output is
Here, if we just try to assign the pointer 'vval' the same address as the constant pointer 'pval', we get a compile time error there itself. As in,
Compilation Error:
Hence, this clearly explains the usage and the need for const_cast operator. Besides, const_cast operator can be used to convert a const object to a non-contant, a volatile variable to a non-volatile, a 'pointer to a constant' to a 'pointer to a modifiable value' and even a 'constant pointer' to a non-constant one.
All these mentioned scenarios are possible visa versa as well.
As the name suggests, re-interpret casts are used to type cast any type to any type. All conversions from a pointer type to any random unrelated pointer type is allowed, and hence making its to be used really carefully. This cast could be leading to unsafe type casts leading to loss of data or unexpected results.
The Syntax:
An Example:
Here, we have two pretty similar in layout classes - 'One' and 'Two', but totally unrelated with each other. Using pointers, we created objects of both of them and checked the data each contains.
Deleting the object pointed by 'two' pointer, which was pointing to an object of class 'Two', we reinterpret cast 'one' pointer which is of type class 'One' pointer to type class 'Two' pointer and assign it to pointer variable 'two'.
Now checking, the data what 'two' points to, lets observe the output:
Oh wow, now 'two' pointer variable points to the object containing the data of 'One'.
However, reiterating, since reinterpret castings are for totally unrelated data types, the programmer is solely responsible for its usage. There might be unexpected results in case of invalid usage. Hence, one should be very sure prior to using reinterpret cast.
A point to be noted that C++ typecasting would be mostly described and used in context of classes, as an effect of C++ being object oriented.
Types of C++ TypeCasting
There are following four types of type casting in C++:
Static-cast
Static cast is generally said to be used for non-polymorphic types. That is, the casting is done on the basis of compile time details. Static cast is done for type casting a base class to derived class and vice versa.
The Syntax:
Code:
1classObject = static_cast<class-1>2classObject;
Code:
class Base
{
public:
int data;
void multiplyData(int var)
{
cout<< "In base class method\n";
data = (data * var);
}
};
class Derived: public Base
{
public:
Derived(Base b)
{
data = b.data;
}
void multiplyData(int var)
{
cout<< "In derived class method\n";
data = (data * (var *2));
}
};
int main()
{
Base base;
base.data = 3;
base.multiplyData(10);
cout<<base.data<<endl;
Derived d = static_cast<Base>(base);
d.multiplyData(10);
cout<<d.data<<endl;
return 0;
}
Code:
Derived d = static_cast<Base>(base);
However, we need to define a copy constructor to leverage the type cast, else it might not know, how and what base object data members to map to the derived object data members. If you donot specify the copy constructor and if the compiler gets confused, it might thrown an error:
Code:
error: conversion from ‘Base’ to non-scalar type ‘Derived’ requested
Anyhow, although you must have guessed, here is the output of the above example:
Code:
In base class method 30 In derived class method 600
Dynamic-cast
Dynamic cast is used for polymorphic types, that is the where types are determined at the runtime. Very apt scenarios are in inheritence where a pointers are type casted dynamically to any class in the inheritence hierarchy.
The syntax:
Code:
lvalue = dynamic_cast<class1>expression
An example to illustrate the usage is
Code:
class Base
{
public:
int data;
virtual void multiplyData(int var)
{
cout<< "In base class method\n";
data = (data * var);
}
};
class Derived: public Base
{
public:
void multiplyData(int var)
{
cout<< "In derived class method\n";
data = (data * (var *2));
}
};
int main()
{
//A pointer pointing to an object of Derived class
Derived *derived = new Derived();
derived->data = 3;
//do some operation
derived->multiplyData(10);
cout<<derived->data<<endl;
// A pointer pointing to an object of Base class
Base *b = new Base();
b->data = 6;
//do some operation
b->multiplyData(10);
cout<<b->data<<endl;
//dynamic cast derived to Base class pointer
b = dynamic_cast<Base*>(derived);
if(b != NULL) // dynamic cast sucess
{
b->data = 12;
//check what b contains now
b->multiplyData(10);
cout<<b->data<<endl;
delete(derived);
}
}
The output being:
Code:
In derived class method 60 In base class method 60 In derived class method 240
Code:
derived = dynamic_cast<Derived*>(b);//fails //derived contains NULL now
Const-cast
The const-cast is used to modify the contant-ness or volatility of any expression. It does not affect the data type of the variable or expression.
The Syntax:
Code:
lvalue = const_cast<type>(expression);
Code:
int cval = 10; const int* pval = &cval; int* vval = const_cast<int *>(pval); (*vval)++; cout<<"Modified val is "<<(*vval)<<endl;
Code:
Modified val is 11
Code:
int cval = 10; const int* pval = &cval; int* vval pval; (*vval)++; cout<<"Modified val is "<<(*vval)<<endl;
Code:
error: invalid conversion from ‘const int*’ to ‘int*
All these mentioned scenarios are possible visa versa as well.
Re-interpret cast
As the name suggests, re-interpret casts are used to type cast any type to any type. All conversions from a pointer type to any random unrelated pointer type is allowed, and hence making its to be used really carefully. This cast could be leading to unsafe type casts leading to loss of data or unexpected results.
The Syntax:
Code:
lvalue = reinterpret_cast<type1>expression
Code:
class One
{
public:
int data;
One()
{
data = 1;
}
};
class Two
{
public:
int data;
Two()
{
data = 2;
}
};
int main()
{
One *one = new One();
Two *two = new Two();
cout<<"one: Data val is "<<one->data<<endl;
cout<<"two: Data val is "<<two->data<<endl;
delete two;
// convert one of type Class Two
two = reinterpret_cast<Two*>(one);
if (two != NULL)
{
//check data of the object pointed by 'two'.
cout<<"two After reinterpret cast : Data val is "<<two->data<<endl;
}
return 0;
}
Deleting the object pointed by 'two' pointer, which was pointing to an object of class 'Two', we reinterpret cast 'one' pointer which is of type class 'One' pointer to type class 'Two' pointer and assign it to pointer variable 'two'.
Now checking, the data what 'two' points to, lets observe the output:
Code:
one: Data val is 1 two: Data val is 2 two After reinterpret cast : Data val is 1
However, reiterating, since reinterpret castings are for totally unrelated data types, the programmer is solely responsible for its usage. There might be unexpected results in case of invalid usage. Hence, one should be very sure prior to using reinterpret cast.