[C++] Casting

Casting one type to another is a main part of programming. C++ language manages data memory more directly than others, therefore ill-performed casting can cause big troubles. C++ designers knew this and provided a set of elaborate cast operators.  

 

1. Casting

Old C-style casting is simple.

double d = 100.5;
int i = (int) d;

C++ style is little different.

double d = 100.5;
int i = int(d); // C++ function style

In addition, C++ provides 4 new cast operators:

  • static_cast
  • reinterpret_cast
  • const_cast
  • dynamic_cast.

Old C style casting covers all 4 new casting types. Therefore it is more error prone.

 

2. Dynamic Casting

The “dynamic_cast” operator performs a run-time cast that verifies the validity of a cast. The purpose of this casting is to perform casts on polymorphic types:

dynamic_cast (expr)

The basic rules are :

  • From (Derived *) to (Derived *) : OK
  • From (Derived *) to (Base *) : OK
  • From (Base *) to (Base *) : OK
  • From (Base *) to (Derived *) : Depends on what a pointer points to
class Base
{
public:
  int x;
  virtual void func() { cout << "Function in Base" << endl; }
};
class Derived : public Base
{
public:
  int y;
  void func() { cout << "Function in Derived" << endl; } // override
};

int main()
{
  Base *bp; Base bobj;
  Derived *dp; Derived dobj;

  dobj.x = 10; dobj.y = 20;

  // 1. From (Derived *) To (Derived *) : OK
  dp = dynamic_cast  (&dobj);
  cout << "From (Derived *) To (Derived *) :";
  if (dp)
  {
    cout << "OK" << endl;
    dp->func(); // Dervied.func()
  }
  else
    cout << "Not OK" << endl;

  // 2. From (Derived *) To (Base *) : OK
  bp = dynamic_cast <Base *> (&dobj);
  cout << "From (Derived *) To (Base *) :";
  if (bp)
  {
    cout << "OK" << endl;
    bp->func(); // Dervied.func()
  }
  else
    cout << "Not OK" << endl;

  // 3. From (Base *) To (Base *) : OK
  bp = dynamic_cast  (&bobj);
  cout << "From (Base *) To (Base *) :";
  if (bp)
  {
    cout << "OK" << endl;
    bp->func(); // Base.func()
  }
  else
    cout << "Not OK" << endl;

  // 4. From (Base *) To (Derived *) : Not OK
  dp = dynamic_cast  (&bobj);
  cout << "From (Base *) To (Derived *) :";
  if (dp)
  {
    cout << "OK" << endl;
    dp->func();
  }
  else
    cout << "Not OK" << endl;
  // 5. (Derived *) to (Base *) and back to (Derived *) : OK
  bp = dynamic_cast <Base *> (&dobj);
  dp = dynamic_cast <Derived *> (bp);
  cout << "(Derived *) to (Base *) and back to (Derived *) :";
  if (dp)
  {
    cout << "OK" << endl;
    dp->func(); // Dervied.func()
  }
  else
    cout << "Not OK" << endl;
  return 0;
}

 

3. Constant Casting

The “const_cast” operator is used to override const or volatile in a cast. The most common use of this operator is to remove const-ness.

const_cast (expr)

int value = 10;
const int *p = &value;
// *p = 100; // error  - cannot change
int *q;
q = const_cast<int *> (p);
*q = 100; // OK
cout << *p << endl; // 100 not 10

 

void func1(const int *p)
{
  //*p = 100; // error
}
void func2(const int *p)
{
  int *q;
  q = const_cast<int *> (p);
  *q = 100; // it's ok, const_cast removes const-ness
}

int _tmain(int argc, _TCHAR* argv[])
{
  int a = 10;
  int *p = &a;

  cout << "a = " << a << endl; // 10
  func1(p);
  cout << "*p = " << *p << endl; // 10
  cout << "a = " << a << endl; // 10

  func2(p);
  cout << "*p = " << *p << endl; // 100
  cout << "a = " << a << endl; // 100

  return 0;
}

As you can see “const_cast” is useful, but it needs to be used with caution. It breaks the purpose of the constant variable.

 

4. Static Casting

The “static_cast” operator performs a non-polymorphic cast. It is used for any standard conversion such as primitive types.

static_cast (expr)

class MyBase
{
public:
  int x;
};
class MyDerived : public MyBase
{
public:
  int y;
};
int main()
{
  MyBase *bp;
  MyDerived *dp; MyDerived d;

  d.x = 10; d.y = 20;

  // 1. C - Old Style Casting
  bp = (MyBase *)&d;

  // 2. C++ - Old Style Casting
  double dval = 5.3;
  bp->x = int (dval);

  // 3. C++ Style Casting
  dp = (MyDerived *) (bp);

  // 4. C++ - static_cast
  dval = 15.2;
  dp->y = static_cast  (dval);

  cout << "dp->x = " << dp->x << endl; // 5
  cout << "dp->y = " << dp->y << endl; // 15

  return 0;
}

 

5. Reinterpret Casting

The “reinterpret_cast” operator converts one type into a fundamentally different type. For example, it can change the pointer type to value type.

reinterpret_cast (expr)

int i = 50;
int *p = &i;

int j = reinterpret_cast<int> (p);
cout << j << endl; // not 50, it will print the pointer (memory) location

Misuse of the “reinterpret_cast” operator can easily be unsafe. It is used with care or not used if possible.

One thought on “[C++] Casting

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s