The nicest example I've seen is switching implementation styles.
You initially used Employee* as your handle type, but you change it to unsigned ints for some reason. The compiler catches most of the changes, but you have one hidden issue:
void Employee::setManager(handle new_manager) {
manager_.removeSubordinate( this );
manager_ = (Manager*)new_manager;
manager_.addSubordinate( this );
}
Now this is bad code on multipule levels ( not exception safe, for example ) but that cast is evil. The compiler will not longer care that the cast has changed from a fairly acceptable, though unsafe, downcast to a completely meaningless integer reinterpretation.
Note that in C++, c-style casts are actually defined in terms of a complex sequence of the named casts.
static_cast : innocent casts. Derived* to Base*, int to float, etc
const_cast : adding or removing const -- no other named casts allow this, which is a good thing
dynamic_cast : checked Base* to Derived*
reinterpret_cast : to be avoided. Only useful for passing T* as the data argument of a C callbacks, since any use other than casting T* to U* and back to T* is undefined or implementation-defined.
Here's another instructive demo:
#include <iostream>
struct B { char c; };
struct D : B { char a; };
int main() {
D d;
std::cout << &d << std::endl;
std::cout << (B*)&d << std::endl;
std::cout << static_cast<B*>(&d) << std::endl;
std::cout << reinterpret_cast<B*>(&d) << std::endl;
std::cout << (void*)&d << std::endl;
std::cout << static_cast<void*>(&d) << std::endl;
std::cout << reinterpret_cast<void*>(&d) << std::endl;
}