TUTORIAL: Casting of variables

  • genux
  • Graduate
  • Graduate
  • User avatar
  • Posts: 106
  • Loc: UK

Post 3+ Months Ago

Casting



Casting is when you convert one variable to another type, or derived class type. For example, if you want to convert a floating point number e.g. 3.4 to a integer value 3 you would need to cast that floating point number to a integer because the compiler cannot return to a variable that is not of the same type as the result on the right had side of the command line.

C style



The classic C style of casting is to put the casting return type in brackets and then place the variable that you want to cast on the right hand side. Example code would be

C Code: [ Select ]
float fl = 3.4;
int intFl = (int)fl;
 
  1. float fl = 3.4;
  2. int intFl = (int)fl;
  3.  


which would result in the intFl value being 3, the 0.4 is disregarded because it is not part of a integer value (only whole numbers, it will round down always).

Different types of casting



There are different types of casting variables from one to another, here is a list of casting types

    const_cast
    static_cast
    dynamic_cast
    reinterpret_cast


And all follow the same parameters

CPP Code: [ Select ]
return value = casting_type<return type>(casting value)
e.g.
int value = static_cast<int>(floatvalue);
 
  1. return value = casting_type<return type>(casting value)
  2. e.g.
  3. int value = static_cast<int>(floatvalue);
  4.  

From the c++ language, these allows for better type checking after you have cast the variable.

const_cast



Constant casting is the way of removing a constant restriction from a variable, sometimes you may want to alter a value that is held within a constant value.

CPP Code: [ Select ]
const int coffee = 3;
int &newCoffees = const_cast<int&>(coffee);
newCoffees += 2;
// you can now add more coffees to your day.
 
  1. const int coffee = 3;
  2. int &newCoffees = const_cast<int&>(coffee);
  3. newCoffees += 2;
  4. // you can now add more coffees to your day.
  5.  


One of the functions within C++ is strstr which returns a pointer to a subpart of the string, the string to search is a constant with the string to search for within the string is also a constant, but you need to return a normal char * to where the subpart of the string is.

Here is code similar to the strstr that will hopefully show a const_cast is abit more usable way.

Code: [ Select ]
#include <iostream>
#include <string.h>

using namespace std;

char* genuxStrStr(const char* p1, const char* p2)
{
   bool found;
   // loop through the first string
   while (*p1)
   {
     // if there is a match between the frist string character and the second string character
     if (*p2 == *p1)
     {
      if (strlen(p2) <= strlen(p1))
      {
       found = true;
       for (int i =0; i < strlen(p2); i++)
       {
        if (p2[i] != p1[i]) {
         found = false;
         break;
        }
       }
       if (found)
       {
        return const_cast<char*>(p1);
       }
      }
     }
     p1++;
   }
   return 0;
}

int main()
{
  char searchStr[] = "hi thre there k ";
  char *pr = genuxStrStr(searchStr, "there");

  // check to make sure it was found.
  if (pr)
  {
   cout << pr << endl;
  }
  else
   cout << "no found" << endl;
}
  1. #include <iostream>
  2. #include <string.h>
  3. using namespace std;
  4. char* genuxStrStr(const char* p1, const char* p2)
  5. {
  6.    bool found;
  7.    // loop through the first string
  8.    while (*p1)
  9.    {
  10.      // if there is a match between the frist string character and the second string character
  11.      if (*p2 == *p1)
  12.      {
  13.       if (strlen(p2) <= strlen(p1))
  14.       {
  15.        found = true;
  16.        for (int i =0; i < strlen(p2); i++)
  17.        {
  18.         if (p2[i] != p1[i]) {
  19.          found = false;
  20.          break;
  21.         }
  22.        }
  23.        if (found)
  24.        {
  25.         return const_cast<char*>(p1);
  26.        }
  27.       }
  28.      }
  29.      p1++;
  30.    }
  31.    return 0;
  32. }
  33. int main()
  34. {
  35.   char searchStr[] = "hi thre there k ";
  36.   char *pr = genuxStrStr(searchStr, "there");
  37.   // check to make sure it was found.
  38.   if (pr)
  39.   {
  40.    cout << pr << endl;
  41.   }
  42.   else
  43.    cout << "no found" << endl;
  44. }


where the return would be

Code: [ Select ]
there k


because that is the first occurrence of the word there within the string.

static_cast



The static cast is mainly used for conversion between normal types, e.g. int, float, double, it can do pointers and also other variables types but the type checking is not as good as a dynamic_cast if you are going to convert between classes.

The basics of the code would be something similar to

CPP Code: [ Select ]
int pi = 3;
float piF = static_cast<float>(pi);
 
  1. int pi = 3;
  2. float piF = static_cast<float>(pi);
  3.  


this will convert from a integer value to a floating point value, without hopefully any bad effects, this is very similar to the C style of conversion, but this has more type checking involved.

dynamic_cast



Dynamic casting is when you want to convert from one class to another, but the only restriction is that the base class has to be polymorphic (e.g. have a virtual method).

Here is a example base class

CPP Code: [ Select ]
class basicClass {
    private :
       int x;
    public:
       basicClass() { x = 0;}    
       void setX(int value ) { x = value;}
 
       virtual int returnX() { cout << "hi from there from the base"; return x;}
 
};
 
  1. class basicClass {
  2.     private :
  3.        int x;
  4.     public:
  5.        basicClass() { x = 0;}    
  6.        void setX(int value ) { x = value;}
  7.  
  8.        virtual int returnX() { cout << "hi from there from the base"; return x;}
  9.  
  10. };
  11.  


and here would be a basic sub class that is inheriting from the basic class

CPP Code: [ Select ]
class subClass : public basicClass {
   private :
     int y;
   public :
     subClass() : basicClass() { y = 0; }
     // new Y to the class
     void setY(int value) { y = value;}
     int returnY() { return y;}
     
     int returnX() { cout << "Hi from the sub class" << endl; return x;}
};
 
  1. class subClass : public basicClass {
  2.    private :
  3.      int y;
  4.    public :
  5.      subClass() : basicClass() { y = 0; }
  6.      // new Y to the class
  7.      void setY(int value) { y = value;}
  8.      int returnY() { return y;}
  9.      
  10.      int returnX() { cout << "Hi from the sub class" << endl; return x;}
  11. };
  12.  


the sub class has also implemented a "y" variable that is very similar to the X in that you can get/set it, but the returnX function also will display which class it is coming from.

If you wanted to create a sub class(subClass) and then convert to the base class (basicClass) as

CPP Code: [ Select ]
subClass *sub = new subClass();
sub->setX(10);
sub->setY(20);
basicClass *basic = new dynamic_cast<basicClass*>(sub);
 
cout << basic->returnY();
 
  1. subClass *sub = new subClass();
  2. sub->setX(10);
  3. sub->setY(20);
  4. basicClass *basic = new dynamic_cast<basicClass*>(sub);
  5.  
  6. cout << basic->returnY();
  7.  


Also the above code would output "hi from the subclass" since that is the actual class that you are really talking to.

the y value is still held within the base class that has been casted to, but you cannot "see" it from the base class calls since there is none in that class, but if you cast back to a subclass you can access the "y" again, because the cast will convert the sub class object into the similar base class (whilst still pointing to the same place in memory) since both have similar things in common.

CPP Code: [ Select ]
subClass *myNewSub = dynamic_cast<subClass>(basic);
cout << myNewSub->returnY();
 
  1. subClass *myNewSub = dynamic_cast<subClass>(basic);
  2. cout << myNewSub->returnY();
  3.  


that would return the Y value of 20 since it has cast the memory back to a subClass structure and in that structure in memory Y equaled 20.

To check the result you just check return value against 0 (NULL) because if has not been able to cast the type it will return 0.

CPP Code: [ Select ]
if (myNewSub == 0)
// dynamic_cast did not work
 
  1. if (myNewSub == 0)
  2. // dynamic_cast did not work
  3.  


When you are casting from a derived class you do not need to dynamic cast because it does not need to "add" anything to the memory location as such, because the area within the memory is big enough to use the base class of the subclass, for example

Code: [ Select ]
subClass *sub = new subClass();
sub->setX(10);
sub->setY(20);

// there is no need for a dynamic casting.
basicClass *basic = sub;

cout << basic->returnY();
  1. subClass *sub = new subClass();
  2. sub->setX(10);
  3. sub->setY(20);
  4. // there is no need for a dynamic casting.
  5. basicClass *basic = sub;
  6. cout << basic->returnY();


you only need to dynamic_cast when you are moving up the chain of inheritance.

You can also check for any bad casting with using a try and catch block, for example
Code: [ Select ]
try {
  *base = dynamic_cast<int>(intvalue);
}
catch (std::bad_cast)
{
  cout << "there was a bad_cast here!!" << endl;
}
  1. try {
  2.   *base = dynamic_cast<int>(intvalue);
  3. }
  4. catch (std::bad_cast)
  5. {
  6.   cout << "there was a bad_cast here!!" << endl;
  7. }


reinterpret_cast



The reinterpret_cast does not really do any type checking apart from does the returning type fit into the bit pattens of the casting type, and that is about it. You can convert a class to a void and then back again without any problems, and also ClassA into a void and then into ClassB, but if ClassB was not similar to ClassA it would just come back with funny data.

CPP Code: [ Select ]
  int *aInt = new int(10);
  void *bVoid = reinterpret_cast<void*>(aInt);
  float *aFloat = reinterpret_cast<float*>(bVoid);
 
  1.   int *aInt = new int(10);
  2.   void *bVoid = reinterpret_cast<void*>(aInt);
  3.   float *aFloat = reinterpret_cast<float*>(bVoid);
  4.  


the aFLoat pointer will be a float variable but the value could be anything, I just did it and the result was 1.4013e-44, which 1e1 equals 10. Where as the dynamic_cast would try and see if the float (aFloat) is similar to the aInt types.

Conclusion



I would personally only with dynamic_cast for classes and static_cast'ing for fundamental types like int, float etc. Better to use the c++ casting methods because at least there is some fundamental checks.

I do really like to have any feedback regarding any tutorial/post, just reply or PM me.. glad to help, better to share knowledge.
  • Anonymous
  • Bot
  • No Avatar
  • Posts: ?
  • Loc: Ozzuland
  • Status: Online

Post 3+ Months Ago

Post Information

  • Total Posts in this topic: 1 post
  • Moderator: Tutorial Writers
  • Users browsing this forum: No registered users and 3 guests
  • You cannot post new topics in this forum
  • You cannot reply to topics in this forum
  • You cannot edit your posts in this forum
  • You cannot delete your posts in this forum
  • You cannot post attachments in this forum
 
 

© 1998-2014. Ozzu® is a registered trademark of Unmelted, LLC.