modoran wrote: |
---|
In C++ we have reinterpret_cast which does the same thing as ( ) |
Ehh...
C style cast is different depending on the context. It can be reinterpret_cast, static_cast, or const_cast. Though usually it's the same as static_cast.
The difference between casting types (and arguably the reason C++ casts were created) is noticable when you get to polymorphism.
For the below examples... let's assume you have the following classes:
1 2 3 4 5
|
// P1 and P2 are polymorphic parent classes
// C is a child class which inherits from both of them
class P1 { virtual ~P1() { } };
class P2 { virtual ~P2() { } };
class C : public P1, public P2 { };
|
The different casts:
reinterpret_cast will take the binary data and merely ('stupidly') reinterpret it as another type. This cast basically does nothing other than change the type.
example:
1 2
|
C obj;
P2* ptr = reinterpret_cast<P2*>(&obj);
|
Here... '&obj' and 'ptr' will be
binary identical... but 'ptr' may or may not be a valid pointer (you should assume it isn't and should not attempt to dereference it). Since the address of &obj may not actually point to P2 data... having a P2 pointer pointing to that address may be invalid.
reinterpret_cast has limited practical uses and should generally be avoided unless you are doing something very specific, and/or are very sure of what you are intending to do.
static_cast will cast between types in an "intelligent" way, making binary adjustments as necessary. Some examples:
1 2
|
P2* ptr = new C; // create a C object, but with a P2 pointer
C* cptr = static_cast<C*>(ptr);
|
Here, static cast will [at compile time], examine the class hierarchy and make any necessary binary adjustments to 'ptr' in order for the resulting cptr to point to the necessary object. This may result in 'ptr' and 'cptr' not being binary identical.... but it will ensure that the address is correct
assuming 'ptr' actually does point to a C object.
Another example:
1 2
|
float foo = 5.0f;
int bar = static_cast<float>(foo);
|
The thing to note with this example is that floating point variables and integral variables are stored very different in memory. It you were to do a straight binary copy (ie: a reinterpret), bar would not be 5, but would probably be several thousand.
So static_cast here does a more intelligent cast, where it determines the integral equivilent of 5 and makes necessary binary adjustments. The end result is that both foo and bar will be 5, even though they will not be binary identical.
dynamic_cast is similar to the first example of static_cast.. where it examines class hierarchies and makes the necessary changes to pointers of polymorphic types. The only difference is it does this at
runtime rather than at
compile time. This way, it ensures that the cast is actually valid.
Example:
1 2 3
|
P2* orig = new P2;
C* stat = static_cast<C*>(orig);
C* dyn = dynamic_cast<C*>(orig);
|
Here... static_cast will assume 'orig' actually points to a C object and will return a pointer pointing to where that object would be in memory. However, since in this example, it
DOESN'T point to a C object (it only points to a P2)... the result is that 'stat' will be a bad pointer.
On the other hand... dynamic_cast will examine 'orig' at runtime, see that it doesn't actually point to a C object, realize it's a bad cast, and will make 'dyn' be a null pointer rather than a bad pointer.
The general rule of thumb is:
- Use static_cast only if you are absolutely sure the pointer you have actually points to the desired type.
- Use dynamic_cast if there is any doubt as to whether or not the pointer points to the intended object.
const_cast Removes 'const' and/or 'volatile' qualifiers on types. This hardly ever has any practical use so I won't go into further details. If you find yourself using const_cast, you are probably doing something very, very wrong.
C-style cast... ie the
(int)
business... is a mish-mash of all of the above.
When it can do a const_cast, that's what it does
Otherwise if it can do a static_cast, that's what it does
Otherwise if it can do a reinterpret_cast, that's what it does
It all depends on the context. Since it's less verbose, less explicit, and therefore less safe than the C++ style casts, it's often avoided in favor of static_cast... even though static_cast requires more typing.