C++ Study Note(2): Cast the light to the darkness

cpp

The old-school C casting is reckless without type checking, to make it worse, the casting is easily overlooked by the maintainers. C++ introduces four cast keywords to rescue: const_cast, static_cast, dynamic_cast, and reinterpret_cast.

The keyword const is a contract between the library developers and users. Dropping the const decorator may incur unexpected behavior, for example:

class Foo
{
public:
        Foo() : dd(0) {}
        // int& bar() { cout << "non-const " << dd << endl; return dd; }
        const int& bar() const { cout << "const " << dd << endl;  return dd; }
private:
        int dd;
};

... ... 
        Foo foo;
        int & x = const_cast<int&>(foo.bar());
        x = 3;

C++ impose the developers to use const_cast to highlight the action, “Warning, warning, the const decoration is dropped…”, the same reason lies in the bool type.

If you are quite confident the type downcasting, static_cast is the right option for you. The compiler would adjust the offset and return a derived class pointer for you in the compile time, aka free overhead. If you could not guarantee the heritage, use dynamic_cast, the runtime would try to down cast the pointer/reference and return a valid pointer/reference if everything is OK, otherwise, a null pointer is returned for pointer down-casting, or a bad_cast exception is raised for the reference casting.

Update: Boost’s developers dislike the inconsistence, a new cast template function, polymorph_cast is introduced for the downcasting and crosscasting:

template
inline Target polymorphic_cast(Source* x BOOST_EXPLICIT_DEFAULT_TARGET)
{
    Target tmp = dynamic_cast(x);
    if ( tmp == 0 ) throw std::bad_cast();
    return tmp;
}

It helps the careless developers to test the validity of the returned pointer, throw an exception if necessary.

If you would like both the type safety from dynamic_cast, and also the performance of static_cast, Boost has another neat cast function, polymorphic_downcast for you such a greedy jerk.

 template
 inline Target polymorphic_downcast(Source* x BOOST_EXPLICIT_DEFAULT_TARGET)
 {
     BOOST_ASSERT( dynamic_cast(x) == x ); // detect logic error
     return static_cast(x);
 }

This cast only works on downcast the pointer, you can tell from the name; it does dynamic_cast in the debug version and static_cast in the release version.

Last and the least, reinterpret_cast, the compiler would just simply pretend the object has a new type without any validation check, offset adjustment; furthermore, it is NOT portable. Use it in caution and make sure you know clearly what you are doing.