|< C & C++ Exception Handling 2 | Main | C++ Typecasting 2 >| Site Index | Download |


 

 

 

 

 

MODULE 22 - C/C++ TYPECASTING 1

Converting the different type of variable data including

the objects and classes either implicitly or explicitly in C & C++ programs

 

 

 

 

 

 

 

 

 

 

 

 

 

My Training Period: xx hours

 

The C and C++ programming skills that supposed to be acquired:

 

  • Understand the basic of type casting.

  • Understand and use the automatic type casting.

  • Understand and use static_cast, const_cast, dynamic_cast and reinterpret_cast.

  • Understand and use the explicit keyword.

  • Source code for the program examples are available in C/C++ Typecasting source codes.

 

22.1  C Typecasting

  • Typecasting is used to convert the type of a variable, function, object, expression or return value to another type.

  • Throughout this tutorial you have encountered many codes that use simple C-style type cast.

  • One of the said advantageous of C++ is the type safe feature.  During the compile or run time there are type checking process that not available in C.  This can avoid a lot of program bugs and unexpected logical errors.

  • In C an expression, expression, of type type, can be cast to another type by using the following syntax:

(type) expression

 

or

 

// look like a function :o) isn’t it?

type (expression)

  • For example:

int p;

double dou;

 

// same as p = int (dou);

p = (int) dou;

  • The previous example used the explicit type conversion that is done by programmers.  Integral type promotion and demotion (automatic type casting, as explained in Module 2); is the implicit type conversion.

  • What ever it is, explicit type conversion should be adopted for good programming habits such as for troubleshooting and readability.

  • The weaknesses in C type cast are listed below:

  1. The syntax is same for every casting operation from simple variables to objects and classes.  For complex type casting, we as well as compiler don’t know the intended purpose of the casting and this will create ambiguity.

  2. When we do the debugging, it is very difficult to locate the related cast problems, although by using the tools provided by the compiler, because there are many codes that use parentheses.

  3. It allows us to cast practically any type to any other type.  This can create many program bugs.  If the program compiled and run successfully, the result still can contain logical errors.

Type caster keyword

Description

static_cast

To convert non polymorphic types.

const_cast

To add or remove the const-ness or volatile-ness type.

dynamic_cast

To convert polymorphic types.

reinterpret_cast

For type conversion of unrelated types.

 

Table 22.1:  Type caster

name_cast<new_type> (expression)

name_cast

either one of the static, const, dynamic or reinterpret

new_type

The result type of the cast.

expression

Expression to be cast

 

22.2  static_cast

name_cast<new_type> (expression)

int p;

double dou;

 

p = static_cast<int> (dou);

#include <iostream>

using namespace std;

 

int main()

{

       int sum = 1000;

       int count = 21;

 

       double average1 = sum/count;

       cout<<"Before conversion = "<<average1<<endl;

 

       double average2 = static_cast<double>(sum)/count;

 

       cout<<"After conversion  = "<<average2<<endl;

       return 0;

}

 

Output:

 

C++ Typecasting inheritance static_cast

#include <iostream>

using namespace std;

 

// enum data type

enum color {blue, yellow, red, green, magenta};

 

int main()

{

       int p1 = 3;

       cout<<"integer type, p1 = "<<p1<<endl;

       cout<<"color c1 = static_cast<color> (p1)"<<endl;

       color c1 = static_cast<color> (p1);

       cout<<"enum type, c1 = "<<c1<<endl;

       return 0;

}

 

      Output:

 

C++ Typecasting static_cast example

 

22.3  const_cast

const_cast<new_type> (expression)

// demonstrates the const_cast

#include <iostream>

using namespace std;

 

int main()

{

       // p = 10 is a constant value, cannot be modified

       const int p = 20;

 

       cout<<"const p = "<<p<<"\nq = p + 20 = "<<(p + 20)<<endl;

       // the following code should generate error, because

       // we try to modify the constant value...

       // uncomment, recompile and re run, notice the error...

       //p = 15;

       //p++;

 

       // remove the const...

       int r = const_cast<int&> (p);

       // the value of 10 should be modified now...

       --r;

       cout<<"Removing the const, decrement by 1,\nNew value = "<<r<<endl;

       return 0;

}

 

Output:

 

C++ Typecasting inheritance const_cast program example

// demonstrates const_cast

#include <iostream>

using namespace std;

 

struct One

{

       // test function...

       void funct1()

       { cout<<"Testing..."<<endl;}

};

 

// const argument, cannot be modified...

void funct2(const One& c)

{

       // will generate warning/error...

       c.funct1();

}

 

int main()

{

       One b;

      

       funct2(b);

       return 0;

}

// remove the const...

One &noconst = const_cast<One&> (c);

cout<<"The reference = "<<&noconst<<endl;

noconst.funct1():

 

Output:

 

C++ Typecasting inheritance const_cast program example

// demonstrates the type casting

#include <iostream>

using namespace std;

 

double funct1(double& f)

{

       // do some work here...

       f++;

       cout<<"f = "<<f<<endl;

       // return the incremented value...

       return f;

}

 

// const argument, can't be modified...

void funct2(const double& d)

{

       cout<<"d = "<<d<<endl;

       // remove the const, use the non-const argument, making function call...

       double value = funct1(const_cast<double&> (d));

       // display the returned value...

       cout<<"value = "<<value<<endl;

}

 

int main()

{

       double c = 4.324;

 

       // first function call...

       funct2(c);

       return 0;

}

 

Output:

 

C++ Typecasting inheritance const_cast program example

// demonstrates the  type casting

#include <iostream>

using namespace std;

 

class One

{

       public:

       void funct()

       {cout<<"Testing..."<<endl;};

};

 

// const and volatile...

const volatile int* Test1;

// const...

const int* Test2;

 

void TestConstVol()

{

       One Test3;

       // remove the const...

       const_cast<One&>(Test3).funct();

       // remove const and volatile...

       const_cast<int*> (Test1);

}

 

int main()

{

       TestConstVol();

       return 0;

}

 

Output:

 

C++ Typecasting const_cast volatile and const program example

// removing the const-ness of the 'this' pointer

#include <iostream>

using namespace std;

 

class Test

{

    public:

        void GetNumber(int);

        // read only function...

        void DisplayNumber() const;

    private:

        int Number;

};

 

void Test::GetNumber(int Num)

{Number = Num;}

 

void Test::DisplayNumber() const

{

       cout<<"\nBefore removing const-ness: "<<Number;

       const_cast<Test*>(this)->Number+=2;

       cout<<"\nAfter removing const-ness: "<<Number<<endl;

}

 

int main()

{

       Test p;

       p.GetNumber(20);

       p.DisplayNumber();

       return 0;

}

 

Output:

 

 

 

 

 

 

 

 

 

 

 

-----------------------------------------------------------------------

 

C++ Typecasting const_cast const this pointer program example

// using mutable to remove the const-ness of the function...

#include <iostream>

using namespace std;

 

class Test

{

       // using mutable

       mutable int count;

       mutable const int* ptr;

       public:

       // read only function can't change const arguments.

       int funct(int num = 10) const

       {

              // should be a valid expression...

              count = num+=3;

              ptr = &num;

              cout<<"After some operation, the new value: "<<*ptr<<endl;

              return count;

       }

};

 

int main(void)

{

       Test var;

       cout<<"Initial value of the argument is: 10"<<endl;

       var.funct(10);

       return 0;

}

 

Output:

 

C++ Typecasting const mutable program example

 

22.4  dynamic_cast

Visual C++ .Net enabling RTTI for dynamic cast

dynamic_cast<new_type> (expression)

C++ Typecasting inheritance dynamic_cast program example

Figure 22.1:  Simple class hierarchy

 

C++ Typecasting inheritance classes

 

Figure 22.2:  Class C with sub-objects B and A

C++ Typecasting inheritance dynamic_cast upcasting program example

 

Figure 22.3: Upcasting, from Derived2 to Derived1/Base1

 

// upcast conversion using dynamic_cast

#include <iostream>

using namespace std;

 

// a base class

class Base1 { };

// a derived class...

class Derived1:public Base1 { };

// another derived class

class Derived2:public Derived1{ };

// dynamic_cast test function...

void funct1()

{

       // instantiate an object…

       Derived2* Test1 = new Derived2;

      

       // upcasting, from derived class to base class,

       // Derived1 is a direct from Base1

       // making Test2 pointing to Derived1 sub-object of Test1

       Derived1* Test2 = dynamic_cast<Derived1*>(Test1);

       cout<<"Derived1* Test2 = dynamic_cast<Derived1*>(Test1);"<<endl;

       if(!Test2)

              cout<<"The conversion is fail..."<<endl;

       else

              cout<<"The conversion is successful..."<<endl;

       // upcasting, from derived class to base class

       // Derived2 is an indirect from Base1

       Base1* Test3 = dynamic_cast<Derived1*>(Test1);

       cout<<"\nBase1* Test3 = dynamic_cast<Derived1*>(Test1);"<<endl;

       if(!Test3)

              cout<<"The conversion is fail..."<<endl;

       else

              cout<<"The conversion is successful..."<<endl;

}

 

int main()

{

   funct1();

   return 0;

}

 

Output:

 

C++ Typecasting inheritance dynamic_cast program example

 

C++ Typecasting inheritance dynamic_cast upcasting program example

Figure 22.4:  void* type, from base to base class

// if new_name is void*, the result of conversion is

// a pointer to the complete object pointed

// to by the expression void* and dynamic_cast

#include <iostream>

using namespace std;

 

// a base class

class Base1

{

       public:

       virtual void funct1(){};

};

// another base class...

class  Base2

{

       public:

       virtual void funct2(){};

};

// dynamic_cast test function...

void funct3()

{

     // instantiate objects…

     Base1 * Test1 = new Base1;

     Base2 * Test2 = new Base2;

    

     // making Test3 pointing to an object of type Base1

     void* Test3 = dynamic_cast<void*>(Test1);

     cout<<"void* Test3 = dynamic_cast<void*>(Test1);"<<endl;

     if(!Test3)

           cout<<"The conversion is fail..."<<endl;

     else

           cout<<"The conversion is successful..."<<endl;

     // making Test3 pointing to an object of type Base2

     Test3 = dynamic_cast<void*>(Test2);

     cout<<"\nTest3 = dynamic_cast<void*>(Test2);"<<endl;

      if(!Test3)

           cout<<"The conversion is fail..."<<endl;

      else

           cout<<"The conversion is successful..."<<endl;

 }

 

int main()

{

    funct3();

    return 0;

}

 

Output:

 

C++ Typecasting inheritance dynamic_cast void pointer program example

 

C++ Typecasting inheritance dynamic_cast downcasting program example

Figure 22.5:  Downcast, from Base1 to Derived1 class

 

// downcast conversion using dynamic_cast

#include <iostream>

using namespace std;

 

// a base class

class Base1 {

       public:

           virtual void funct1(){ };

};

// a derived class...

class Derived1:public Base1 {

       public:

           virtual void funct2(){ };

};

// a dynamic_cast test function...

void funct3()

{

       // instantiate objects…

       Base1* Test1 = new Derived1;

       Base1* Test2 = new Base1;

       // making Test1 pointing to Derived1

       Derived1* Test3 = dynamic_cast<Derived1*>(Test1);

       cout<<"Derived1* Test3 = dynamic_cast<Derived1*>(Test1);"<<endl;

       if(!Test3)

              cout<<"The conversion is fail..."<<endl;

       else

              cout<<"The conversion is successful..."<<endl;

       // should fails coz Test2 pointing

       // to Base1 not Derived1, Test4 == NULL

       Derived1* Test4 = dynamic_cast<Derived1*>(Test2);

       cout<<"\nDerived1* Test4 = dynamic_cast<Derived1*>(Test2);"<<endl;

       if(!Test4)

              cout<<"The conversion is fail..."<<endl;

       else

              cout<<"The conversion is successful..."<<endl;

       // reconfirm, should be NULL pointer…

       cout<<"Should be NULL pointer =  "<<Test4<<endl;

}

 

int main()

{

 

   funct3();

   return 0;

}

 

Output:

 

C++ Typecasting inheritance dynamic_cast downcasting program example

 

C++ Typecasting inheritance dynamic_cast downcasting program example

Figure 22.6:  Multiple conversion, from Derived3 to Base1

 

tenouk fundamental of C++ object oriented tutorial

 

 

 

 

 

 

 

 

 

 

 

Further typecasting related reading:

 

  1. Source code for the program examples are available in C/C++ Typecasting source codes.

  2. Check the best selling C / C++, Object Oriented and pattern analysis books at Amazon.com.

 

 

 

 

 

|< C & C++ Exception Handling 2 | Main | C++ Typecasting 2 >| Site Index | Download |


C++ Typecasting:  Part 1 | Part 2