SatView: Pointer Perfect, Part 1 - Dynamic_cast
(Page 5 of 5 )
The dynamic_cast is used to safely cast up and down an inheritance hierarchy (e.g. from base object pointer into a derived object pointer) and relies on compile time and run time information.
When dynamic_cast fails on a pointer during run time, it returns NULL, and when it fails on references it throws an exception. This feature can be used during run time to determine if a cast succeeded or not, but you do take a small performance penalty. For this very reason the dynamic_cast is often used to implement the generic Visitor pattern; but if you don’t want that performance penalty you can still implement the Visitor pattern without dynamic_cast (albeit not as generic).
T t = dynamic_cast<T>(expression);
e.g. Derived *pPtr2 = dynamic_cast<Derived*>(pBase);
Note that you can never cast a base object into a derived object when it is an instantiation of that very base class! You can not make the object any larger than it actually is: I may have a barrel of oil, but how could I just bluntly assume it is unleaded gasolinel? I can static_cast it into unleaded gasoline or diesel and try to run my car on it, but this most definitely would fail.
Reinterpret_cast
Your last resort might be the reinterpret_cast, which just blindly casts type A into type B. Remember the void* I mentioned in the legacy C API? That would be a typical scenario where you would encounter a reinterpret_cast.
T t = reinterpret_cast<T>(expression);
Another example might be the need to cast between function pointer types. Let's say you have the following code:
Typedef void (*FuncPtr)(); // FuncPtr is a function pointer
FuncPtr array[5]; // this is an array of 5 FuncPtrs
Now it won’t be a problem to put a void function(); as a FuncPtr into that array, but what happens when you want to place int function(); as a FuncPtr in there? Then this is what you need to make the compiler do your bidding:
array[0] = reinterpret_cast<FuncPtr>(&foo);
And realize that this is not showing a lot of respect for identity; I would even say that this code is being quite rude. Please stay away from dark, muddy, treacherous waters like these.
The `void* operator'
Once I ran into a statement that quite puzzled me… it read:
if (!myObj) {/*something is wrong*/}
What puzzled me was that myObj was an object and how can an object be evaluated as true or false? It turns out that the compiler uses the void* operator as a last attempt to make sense of this through implicit conversion.
This can come in real handy, since you can query whether an object is valid or not. The STL allows you to validate iostreams this way; you can find in the file xiosbase:
operator void *() const
{ // test if any stream operation has failed
return (fail() ? 0 : (void*)this);
}
As you see in the code above, when a certain state/condition isn’t met the operator returns 0, resolving to false in our statement (and yes a C++ cast could have been used instead of the C-style cast).
Conclusion
This concludes part one of our series on the SatView project. Stay tuned for the next article, where we'll be studying construction and deconstruction in C++. Until next time!
| DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware. |