article

Casts Made Easy!

Email
Submitted on: 1/3/2015 2:53:00 AM
By: Andrew Hull (from psc cd)  
Level: Intermediate
User Rating: By 14 Users
Compatibility: C++ (general), Microsoft Visual C++, Borland C++, UNIX C++
Views: 1276
 
     A tutorial that explains and gives examples for static_cast, reinterpret_cast, const_cast, and dynamic_cast.

 
				

Casts Made Easy!

 

In C, casting was easy. You could cast like you called a function:

int i = int('A');

You can also do this in C++. But the only reason it's there is for backwards compatibility with C. Casting like this will eventually cause havoc in a large program, and it also only provides support for primitive types. In C++, there is a set of 4 ANSI C++ casts: static_cast, reinterpret_cast, const_cast, and (the much feared) dynamic_cast. Here I will provide an explanation and example for each cast, to make them easier to understand and possibly save some programs using C casting :)


First, the simplest and most common, static_cast. This cast simply converts from one data type to another. The syntax is:

static_cast<new_type>(argument);

where new_type is the type to be converted to, and argument is the data you wish to convert. Converting my earlier example from C to C++ yields:

int i = static_cast<int>('A');

Note that new_type can be any data type, primitive or user-defined. argument can also be a variable:

char letter = 'A';
int i = static_cast<int>(letter);

That's all there really is to static_cast.


The next type of (and hardest to spell) cast is reinterpret_cast. Unlike static_cast, reinterpret_cast doesn't actually change any data, it causes the data to be reinterpreted, or looked at differently, by the compiler. The most common use of reinterpret_cast is casting a void* pointer, such as the one returned from malloc():

int* num = reinterpret_cast<int*>(malloc(100));

But then again, who needs malloc() when you've got new? reinterpret_cast can be dangerous, however, like in this example:

int num = 5;
int* pNum = &num;
double* pDouble = reinterpret_cast<double*>(pNum);

cout << *pDouble << endl;

This outputs integer data as if it were double (or floating point) data. Nothing but bad things can result from that! You'll probably get a lot of garbage printed to the screen.

The moral here? Be careful with reinterpret_cast!


Next we'll look at const_cast. const_cast is for adding/removing const from a variable. There usually isn't a reason to do this, and if there is, it's probably bad programming. However, every so often there's a situation that you just can't get around, and have to use const_cast. (sorta like goto). Here's a simple example:

void Display(int* data)
{
cout << *data << endl;
}

int main()
{
const int num = 5;
Display(const_cast<int*>(&num));

return 0;
}

If you don't use const_cast here, the compiler will give you an error along the lines of "no match for function..." because const data can't be passed into non-const function data. Redundant? Yes. Avoidable? Yes. Occasionally necessary? Yes.


Finally, it's time to tackle the one no one else wants to: dynamic_cast. There's a lot of confusion over what it does, why to use it, when to use it, etc. The formal (i.e. newbie-scaring) description says that it "is a polymorphic cast that verifies the runtime type of the object being cast". Ouch. To make it clearer, consider this example:

class Base
{
public
virtual void DoSomething() {cout << "Base" << endl;}
};

class Derived : public Base
{
public:
virtual void DoSomething() {cout << "Derived" << endl;}
};

int main()
{
Derived derived;
Base* pBase = &derived;
// the base pointer points to a derived object. Legal, but confusing.

Derived* pDerived = dynamic_cast<Derived*>(pBase);
// because pBase is actually a pointer to a Derived at runtime, the
// cast succeeds and pDerived is assigned the value of pBase

if (pDerived)
pDerived->DoSomething();

else
cout << "Bad cast" << endl;

return 0;
}

 

In this example, the pointer to Base was assigned the address of a Derived object. That's legal. Then, a pointer to a Derived is declared. A check is performed with dynamic_cast: if, at runtime, the argument (pBase) is of type new_type (Derived), then dynamic_cast returns a pointer to Derived with the value pBase. So, pDerived is assigned the value of a base pointer which without a cast would be impossible.

dynamic_cast returns NULL if the cast fails, so to prevent a memory leak ALWAYS check if the cast succeeded with an if...else. Classes used with dynamic_cast must have at least one virtual function.


Well, that's it. I hope you've learned something from all of this! Please leave any comments/feedback that come to mind, everything is appreciated! If you need anything cleared up, please feel free to email me at kavutitan26@yahoo.com. Enjoy!

->Andrew-<


Other 2 submission(s) by this author

 


Report Bad Submission
Use this form to tell us if this entry should be deleted (i.e contains no code, is a virus, etc.).
This submission should be removed because:

Your Vote

What do you think of this article (in the Intermediate category)?
(The article with your highest vote will win this month's coding contest!)
Excellent  Good  Average  Below Average  Poor (See voting log ...)
 

Other User Comments


 There are no comments on this submission.
 

Add Your Feedback
Your feedback will be posted below and an email sent to the author. Please remember that the author was kind enough to share this with you, so any criticisms must be stated politely, or they will be deleted. (For feedback not related to this particular article, please click here instead.)
 

To post feedback, first please login.