Login

Username:

Password: 

Join us Now |  Forgot Password? | Forgot UserName?

C++

Learn step by step



C++ Type Conversions

What is type conversion ?

It is the process of converting one type into another. Or we can say, converting an expression of a given type into another is called type casting.

How to achieve this

There are 2 ways of achieving the type conversion namely:

  • Automatic Conversion otherwise called Implicit Conversion
  • Type casting otherwise called Explicit Conversion

Automatic Conversion otherwise called Implicit Conversion

Almost every compiler makes use of what is called automatic typecasting. It automatically converts one given type into another type. If compiler converts a type it will normally give a warning. Example this warning: conversion from ‘double’ to ‘int’, possible loss of data.

The problem with this is, that we get a warning (normally we want to compile without warnings and errors) and we are not in control. With control we mean, we did not decide to convert to another type, the compiler did. Also possible loss of data could be unwanted.

This is not done by any conversions or operators. Or we can say, the value gets automatically converted to the specific type to which it is assigned.

#include <iostream>
using namespace std;
void main()
{
short x=6000;
int y;
y=x;
}

In above example the data type short namely variable x is converted to int and is assigned to the integer variable y.

Therefore as above it is possible to convert short to int, int to float and so on.

Type casting otherwise called Explicit Conversion

Explicit conversion is done using type cast operator and the general syntax for doing this is : datatype (expression);

Here in above datatype is the type which the programmer wants the expression to gets changed as.

The C and C++ languages have ways to give us back control. This is done with what is called an explicit conversion. Sure we may still lose data, but we decide when to convert to another type and we don’t get any compiler warnings.

Let us take a look at an example that uses implicit and explicit conversion:


#include <iostream>
using namespace std;

int main()
{
int a;
double b=2.55;

a = b;
cout << a << endl;

a = (int)b;
cout << a << endl;

a = int(b);
cout << a << endl;
}

Output

the output of all cout statements is 2.

The first conversion is implicit conversion (the compiler decides.) As explained before, compiler should give a warning.

The second conversion is a explicit typecast, in this case the C style explicit typecast.

The third conversion is also an explicit typecast, in this case the C++ style explicit typecast.

Four typecast operators

The C++ language has 4 typecast operators:

  • static_cast
  • reinterpret_cast
  • const_cast
  • dynamic_cast

Static_cast

Automatic conversions are common in every C++ program.
We have:

  • Standard conversion. For example: from short to int or from int to float.
  • User defined conversions (Class conversions.)
  • Conversion to the base class from derived class.

Operator static_cast can be used for all these types of conversion.

int a = 5;
int b = 2;
double out;

// typecast a to double
out = static_cast<double>(a)/b;

It may take some time to get used to the notation of the typecast statement. (rumour goes that Bjarne Stroustrup made it difficult on purpose, to discourage the use of typecasting.) Between the angle brackets we place to which type the object should be casted. Between the parentheses we place the object that is casted.

It is not possible to use static_cast on const objects to non-const objects. For this we have to use const_cast. (Further down we take a look at the const_cast.)

If an automatic conversion is valid (from enum to int for instance) then we can use static_cast to do the opposite (from int to enum.)
For instance:

enum my_numbers { a=10, c=100, e=1000 };

const my_numbers b = static_cast<my_numbers> (50);
const my_numbers d = static_cast<my_numbers> (500);

Note: We add some new values (b and d). These are type-cast from int to enum.

Reinterpret_cast

Operator reinterpret_cast is used for casts that are not safe:

  • Between integers & pointers
  • Between pointers & pointers
  • Between function-pointers & function-pointers

For example the typecast from an integer to a character pointer:

char *ptr_my = reinterpret_cast<char *>(0xb0000);

Note: example above uses a fixed memory location.

If we use the reinterpret_cast operator on a null-pointer then we get a null-pointer of the asked type:

char *ptr_my = 0;
int *ptr_my_second = reinterpret_cast<int *>(ptr_my);

The reinterpret_cast is almost as dangerous as an “old fashion”. Only guarantee is that we get, if we cast an object back to the original data-type (before the first cast) then the original value is also restored (of course only if the data-type was big enough to hold the value.)

The only difference with an old fashion cast is that const is respected. This means that reinterpret_cast can not be used to cast a const object to non-const object.
For instance:

char *const MY = 0;

// not valid because MY is a const!!
int *ptr_my = reinterpret_cast<int *>( MY);
Const_cast

The only way to cast away the const properties of an object is to use const_cast. Take a look at example:

char *const MY = 0;

// not valid because MY is a const!!
int *ptr_my = reinterpret_cast<int *>( MY);

The use of const_cast on an object doesn’t guarantee that the object can be used (after the const is cast away.) Since it is possible that the const-objects are put in read-only memory by the program.

The const_cast operator can not be used to cast to other data-types, as it is possible with the other cast functions.
Take a look at the next example:

int a;

const char *ptr_my = "Hello";

a = const_cast<int *>(ptr_my);

a = reinterpret_cast<const char*>(ptr_my);

a = reinterpret_cast<int *>(const_cast<char *>(ptr_my) );

Note: casting from const char * to int * isn’t very good (not to say a very dirty trick.) Normally we won’t do this.

The first statement (const_cast) will give an error, because the const_cast can not convert the type. The second statement (reinterpret_cast) will also give an error, because the reinterpret_cast can not cast the const away. The third statement will work (mind the note. It is a dirty trick, better not to use it.)

dynamic_cast

dynamic_cast can only be used with pointers and references to classes (or with void*). Its purpose is to ensure that the result of the type conversion points to a valid complete object of the destination pointer type.

This naturally includes pointer upcast (converting from pointer-to-derived to pointer-to-base), in the same way as allowed as an implicit conversion.

But dynamic_cast can also downcast (convert from pointer-to-base to pointer-to-derived) polymorphic classes (those with virtual members) if -and only if- the pointed object is a valid complete object of the target type.


// dynamic_cast
#include <iostream>
#include <exception>
using namespace std;

class Base { virtual void dummy() {} };
class Derived: public Base { int a; };

int main () {
try {
Base * pba = new Derived;
Base * pbb = new Base;
Derived * pd;

pd = dynamic_cast<Derived*>(pba);
if (pd==0) cout << "Null pointer on first type-cast.\n";

pd = dynamic_cast<Derived*>(pbb);
if (pd==0) cout << "Null pointer on second type-cast.\n";

} catch (exception& e) {cout << "Exception: " << e.what();}
return 0;
}

Output

Null pointer on second type-cast.

Compatibility note: This type of dynamic_cast requires Run-Time Type Information (RTTI) to keep track of dynamic types. Some of the compilers support this feature as an option which is by default disabled. This needs to be enabled for runtime type checking using dynamic_cast to work properly with these types.

The code above tries to perform two dynamic casts from pointer objects of type Base* (pba and pbb) to a pointer object of type Derived*, but only the first one is successful. Note their respective initializations:

Base * pba = new Derived;
Base * pbb = new Base;

Even though both are pointers of type Base*, pba actually points to an object of type Derived, while pbb points to an object of Base type. So, when their respective type-casts are performed using dynamic_cast, pba is pointing to a full object of Derived class, whereas pbb is pointing to an object of Base class, which is an incomplete object of class Derived.

When dynamic_cast cannot cast a pointer because it is not a complete object of the required class -as in the second conversion in the previous example- it returns a null pointer to indicate the failure. If dynamic_cast operator is used to convert to a reference type and the conversion is not possible, an exception of bad_cast type is thrown instead.

dynamic_cast can also perform other implicit casts allowed on pointers: casting null pointers between pointers types (even between unrelated classes), and casting any pointer of any type to a void* pointer.



Related Videos