Type Conversions In C++

Check Out The Various Type Conversions Supported In C++.

We hope you should be aware of all the data types that are available in C++ from our earlier tutorials. At times, a need may arise such that we need to convert one type to another. This is called type conversion or type-casting.

In this tutorial, we will discuss the various type conversions supported in C++.

=> Click Here For The Free C++ Course.

Type Conversions in C++

Type Conversions

C++ supports two types of Type Conversions:

  • Implicit Type Conversion: Implicit type conversion is automatic. There is no interference from the user in this type of conversion and the compiler directly carries out the conversion. Conversion is usually done when in expression there is more than one type of data. But generally, in this type of conversion, there is a possibility for loss of data, loss of signs or overflow of data.
  • Explicit Type Conversion: Explicit type conversion is user-defined and is normally called “type-casting”. Here the user casts or converts a value of one data type to another depending on the requirements. These type of conversions are safer.

Now we will see both the types of type conversion in detail.

Implicit Conversion

In implicit conversion, the compiler carries out the conversions from one data type to another whenever an expression has more than one data type. In order to prevent loss of data, all the variables of the other data types are converted to the largest data type. This is called promotion.

Let us understand Implicit conversion using a code Example.

#include <iostream>
using namespace std;

int main() {
                int num = 10;
                char ch = 'A';
                cout<<"10 + 'A' = "<<num + ch<<endl;

                float val = num + 'a';
                cout<<"float val(10 + 'a') = "<<val<<endl;

                short var = 1000;
                int var_int = var;
                cout<<"var_int = "<<var_int;
                return 0;
}

Output:

10 + ‘A' = 75

float val(10 + ‘a') = 107

var_int = 1000

The above code example demonstrates implicit conversion. We have declared an integer and a character variable with values 10 and ‘A’ respectively. When we add up these two variables, an implicit conversion takes place.

As integer is the larger type in this expression, the character variable value ‘A’ is converted to its integer equivalent i.e. value 65(ASCII value). Thus the result of the expression is 75.

In the next expression, we add integer and character (‘a’ ->97) and then assign the result to float. Thus the result of the expression is implicitly converted to float by the compiler.

In the third expression, a short int variable is converted to integer implicitly.

Note: In case of implicit conversions, if the compiler detects a potential loss of data, then it might flash a warning to this effect.

Explicit Conversion

Explicit conversion is also known as “type-casting” as we ‘cast’ one data type to another data type. Here, the users explicitly define the casting, unlike implicit conversion where the compiler internally carries out the conversion.

We can perform Explicit conversion in two ways:

#1) Using Assignment Operator

Explicit conversion or typecasting using assignment operator in a way is performed forcefully. Here we cast or convert one data type to another data type by using the assignment operator.

The general syntax is:

 (data type) expression;

The Following Example explains this:

#include <iostream>
#include <string>
using namespace std;

int main()
{
  int sum;
  double salary = 4563.75;
  sum = (int)salary + 1000;
  cout<<"Sum = "<<sum<<endl;
 
 double comp = (double)sum + 0.20;
 cout<<"Comp = "<<comp;
return 0;
}

Output:

Sum = 5563
Comp = 5563.2

We have shown explicit casting using the assignment operator in the above example. First, we cast the variable salary of type double to an integer type. Next, we cast the integer variable sum to a double type.

As shown in the output, the type to which we cast indicates the final type of the result of the expression.

This is advantageous as the user can change the type of expression as per the requirements.

#2) Using Cast Operator

In this type of casting, we use a “cast operator” which is a unary operator to change from one type to another.

Types of Casting

We have the following types of casting depending on the cast operator we use:

#1) Static Cast

The static cast is the simplest among all typecasting using the cast operator. The static cast is able to perform all the conversions that are carried out implicitly. It also performs conversions between pointers of classes related to each other (upcast -> from derived to base or downcast -> from base to derived).

Apart from the above-listed conversions, the static cast is also able to convert any pointer to void*.

The static cast is the compiled time cast. This means there is no check made at runtime to see if the cast performed is valid or not. Thus it remains the responsibility of the programmer to ensure that the conversion was safe and valid.

In other words, the user has to ensure that the object converted was full with respect to the destination data type.

We specify a static cast as follows:

static_cast <new_type> (expression)

Let us understand Static cast using an Example.

#include <iostream>
using namespace std;
int main()
{
   
  double df = 3.5 * 3.5 * 3.5;
  cout<<"Before casting: df = "<<df<<endl;
 
  int total = static_cast<int>(df);
  cout <<"After static_cast:total = "<<total;
}

Output:

Before casting: df = 42.875
After static_cast:total = 42

Thus in the above example, we have computed the value of type double. Then we apply a static_cast to this value to convert it to an integer type. In the output, we see that the value is truncated after we cast it to int.

Now let us modify the above code as follows:

#include <iostream>
using namespace std;
int main()
{
 
  double df = 3.5 * 3.5 * 3.5;
  cout<<"Before casting :df = "<<df<<endl;
 
  int total = static_cast<int>(df);
  cout <<"After static_cast:total = "<<total;
 
  char c = 'A';
  int* pq = static_cast<int*>(&c);
  cout<<*pq;
}

In the above example, we have slightly modified the code to include a character variable with value ‘A’. Then we declare an integer pointer and apply a static cast to convert a character to an integer pointer.

When we compile this program we get the following output.

In function ‘int main()':
10:35: error: invalid static_cast from type ‘char*' to type ‘int*'

The program gives an error for the static cast performed as it is invalid. Thus static cast only allows valid type casting or conversions and gives an error when we try to carry out some undesirable typecasting.

#2) Dynamic Cast

Dynamic cast is a runtime cast performed to check the validity of the cast. Dynamic cast is performed only on class pointers and references. The expression returns a NULL value if the cast fails.

The dynamic cast uses a mechanism known as RTTI (Runtime Type Identification). RTTI makes all the information about the object’s data type available at runtime and is available only for the classes that have at least one virtual function (polymorphic type). RTTI allows determining the object type at runtime or at the time of execution.

Let us try one Example to understand Dynamic cast.

#include <iostream>
#include <string>
using namespace std;

class base {public: virtual void print(){}};
class derived:public base{};

int main()
{
  base* b = new derived;
  derived* d = dynamic_cast<derived*>(b);
 
   if(d != NULL)
       cout<<"Dynamic_cast done successfully";
  else
       cout<<"Dynamic_cast not successful";
}

In this program, we have defined two classes, base with a virtual function and derived having a base class, base.

In the main function, we create a derived class object pointed to by the base class pointer. Then we perform dynamic_cast on the base pointer pointing to a derived class to cast it to a derived class pointer.

As in the base class, the base is polymorphic (contains virtual function), the dynamic_cast is successful.

Note: If we remove the virtual function from the above class, then dynamic_cast will fail as RTTI information for the objects will not be available.

The dynamic cast has an overhead of type-safety at runtime.

#3) Reinterpret Cast

This type of cast is most dangerous to use as it works on any type of object without the classes being related to each other.

Reintepret_cast works on any pointers and it converts a pointer of any type to any other type irrespective of whether the pointers are related to each other or not. It does not check if the pointer or the data pointed to by the pointer is same or not.

The cast operator <reinterpret_ cast> takes only one parameter, the source pointer to convert to and does not return any value. It simply converts the pointer type.

We should not use <reinterpret_cast> unless required. We usually typecast the source pointer to its original type.

We use <reinterpret_cast> mostly to work with bits. When <reinterpret_cast> is used on Boolean values, boolean values are converted to integer values i.e. 1 for true and 0 for false.

Let us see an Example of Reinterpret cast:

#include <iostream>
using namespace std;
 
int main()
{
  int* ptr = new int(97);
  char* ch = reinterpret_cast<char*>(ptr);
  cout << ptr << endl;
  cout << ch << endl;
 
  cout << *ptr << endl;
  cout << *ch << endl;
  return 0;
}

Output:

0x3ef3090
a
97
a

In the above example, we have declared an integer pointer ptr pointing to value 97. Next, we declare a character pointer ch and cast ptr to it using <reinterpret_cast>.

Next, we print various values. The first we print is ptr that points to an integer location. Hence it prints an address.

The next value ch contains value 97 and thus it prints ‘a’ which is ASCII equivalent of 97. The next value “*ptr” holds the value 97 while “*ch” holds ASCII equivalent of 97 i.e. ‘a’ as it cast using the reinterpret_cast.

#4) Const Cast

The cast operator <const_cast> is used to change or manipulate the constness of the source pointer. By manipulation, we mean that it can be either to set constness to a non-const pointer or remove constness from a const pointer.

The condition to successfully cast <const_cast> operator is that the pointer and the source which is cast should be of the same type.

Let us take an example to understand this.

#include <iostream>
using namespace std;
 
int printVal(int* ptr)
{
  return(*ptr*10);
 
}
 
int main(void)
{
  const int value = 10;
  const int *ptr = &value;
  int *ptr_cast = const_cast <int *>(ptr);
  cout <<"printVal returned = "<< printVal(ptr_cast);
 
  return 0;
}

In this example, we see that the function ‘printVal’ accepts a non-const pointer. In the main function, we have a const variable ‘value’ assigned to the const pointer ptr.

In order to pass this const pointer to the function printVal, we cast it by applying <const_cast> in order to remove the constness. Then we pass the pointer ptr_cast to the function to get the desired results.

Conclusion

With this, we will wrap up this topic of type conversion in C++. We have seen all about implicit and explicit conversions that are used in C++.

However, one should be aware that in order to prevent loss of data and other such difficulties, conversions or typecasting should be applied wisely only if the situation necessitates the use.

=> Watch Out The Beginners C++ Training Guide Here.