Recently I noticed my knowledge about C++ cast operators had been far from complete. For instance, I had thought static_cast is only for static upcasts(or downcasts also?) in an inheritance hierarchy. And for some legitimate casts between primitive types(like between int and float or between int and unsigned int), I used the C-style cast, still. I was not sure about how new cast operators are precisely mapped to the old C-style, either. So here is my shot at finally clarifying all these.
Categories
Errors possible
- Es : compile error
 - Er: run-time check failure
 
  
- an exception when casting a reference
 - returing nullptr when casting a pointer
 
 - Ec : run-time crash when using the converted
 
Conversions supported
- Cprim: between primitive types : int <-> float, int <-> unsigned int
 
  
- built-in conversion rules apply
 
 - pointer(reference) types
 
  
- Cbase: pointer to a linearly related type(upcast/downcast) : CDerived* <-> CBased*
 
  
- a proper pointer arithmetic applies if a multiple inheritance used
 
 - Cvoid : void pointer : void* <-> int*
 - Cconst : removing const/volatile type qualifiers : const int* <-> int*
 - Cetc : Any other cases : int* <-> float*
 
 - Cbase: pointer to a linearly related type(upcast/downcast) : CDerived* <-> CBased*
 
  
 
Casts
static_cast<>
- Cprim, Cbase, Cvoid
 - Es if Cconst, Cetc tried
 - A possible Ec if an invalid downcast tried 
e.g. CBase* pB = new CBase(); CDerived* pD = static_cast<CDerived*>(pB); 
reinterpret_cast<>
- Cbase, Cvoid, Cetc
 - Es if Cprim, Cconst tried
 - A possible Ec if Cbase tried(because a proper point arithmetic isn’t applied)
 
dynamic_cast<>
- Cbase, dynamic_cast<void*>
 
  
- The latter returns a pointer to the complete(i.e. most-dervied) object.
 
 - Es if Cprim, Cvoid, Cconst, Cetc
 - A possible Er if a downcast of Cbase tried and its run-time check fails
 
const_cast<>
- Cconst
 - Es if Cprim, Cbase, Cvoid, Cetc
 
C-style cast
- A C-style cast is defined as the first of the following which succeeds:
 
  
- const_cast
 - static_cast
 - static_cast, then const_cast
 - reinterpret_cast
 - reinterpret_cast, then const_cast
 
 
Conclusion
- Never use the C-style cast any more. You can use one among (or an combo of) const_cast, static_cast, reinterpret_cast depending on your exact need at that time.
 - dynamic_cast is a complete new thing in C++ and use it sparingly since it has a run-time cost and a need for it might be a symptom of some bad underlying design(though this aspect of it has not been discussed in this article).
 - C++ is too deep (for a mere mortal to figure all its nooks and crannies).
 
References
(This article has also been posted to my personal blog.)
Update – dynamic_cast<void*> and the fourth reference added