Typecasting in C++ allows us to perform conversion between types.
C-Style Cast
This was carried forward from C- language. Compiler does not perform type checking and hence this type of cast can result in run time errors/ undefined behavior. Therefore It is best to avoid them in the program. For example, consider the following.
Example 1
#include <iostream> | |
#include <string> | |
using namespace std; | |
struct A{ | |
int first; | |
int second; | |
A(int first, int second):first(first), second(second){} | |
}; | |
struct B{ | |
string third; | |
string fourth; | |
}; | |
int main() { | |
A* a = new A(1,2); | |
B* b = (B*)a; | |
cout<<b->third; //Run-time error | |
return 0; | |
} |
Example 2
#include <iostream> | |
using namespace std; | |
int main(){ | |
char a = 'c'; | |
int *b = (int*)&a; | |
cout<<*b; //Undefined behavior because integer pointer tries to access 4 bytes of memory although only 1 byte belongs to it. | |
return 0; | |
} |
C++ introduced four new casting operators – static_cast, dynamic_cast, const_cast and reinterpret_cast.
static_cast
static_cast addresses many of the pitfalls associated with the C-style cast. It performs thorough type checking at compile time and throws an error when there is a type mismatch. The earlier examples can therefore be changed to the following. Both the programs will throw compile time errors.
Example 1
#include <iostream> | |
#include <string> | |
using namespace std; | |
struct A{ | |
int first; | |
int second; | |
A(int first, int second):first(first), second(second){} | |
}; | |
struct B{ | |
string third; | |
string fourth; | |
}; | |
int main() { | |
A* a = new A(1,2); | |
B* b = static_cast<B*>(a); //Compiler Error | |
cout<<b->third; | |
return 0; | |
} |
Example 2
#include <iostream> | |
using namespace std; | |
int main(){ | |
char a = 'c'; | |
int *b = static_cast<int*>(&a); //Compiler Error | |
cout<<*b; | |
return 0; | |
} |
static_cast does not work well with inheritance. When we have a pointer to a base class that may or may not be pointing to an object of its derived class and we try to explicitly convert this pointer to a pointer of the derived class, static_cast will happily do the conversion for us. This is not desirable as the base class pointer may as well be pointing to an object of the base class.
#include <iostream> | |
using namespace std; | |
class Base_Class { | |
public: | |
virtual void func() {} | |
}; | |
class Derived_Class :public Base_Class { | |
public: | |
void func() {} | |
}; | |
int main() { | |
Base_Class * a = new Base_Class(); | |
Derived_Class *b = static_cast<Derived_Class*>(a); | |
if (!b) cout << "b is nullptr"; | |
else cout << "b is not nullptr"; | |
cin.get(); | |
} |
Output:
b is not nullptr
dynamic_cast
dynamic_cast addresses the pitfalls associated with compile time type checking. It performs type checking during run-time and is able to catch the above incorrect type conversion. dynamic_cast returns a null pointer when the cast performed is illegal.
#include <iostream> | |
using namespace std; | |
class Base_Class { | |
public: | |
virtual void func() {} | |
}; | |
class Derived_Class :public Base_Class { | |
public: | |
void func() {} | |
}; | |
int main() { | |
Base_Class * a = new Base_Class(); | |
Derived_Class *b = dynamic_cast<Derived_Class*>(a); | |
if (!b) cout << "b is nullptr"; | |
else cout << "b is not nullptr"; | |
cin.get(); | |
} |
Output:
b is nullptr
There are two other casting operators in C++: const_cast and reinterpret_cast. const_cast allows us to remove the ‘const’ and ‘volatile’ properties of types. It works with pointers and references.
Leave a Reply