Using static_pointer_cast<T>(..) and dynamic_pointer_cast<T>(..)

This demonstrates how to use static_pointer_cast<T>(..) and dynamic_pointer_cast<T>(..). It is like the previous post which shows how to use const_pointer_cast<T>(..).

First the headers and some class declarations:

# include <boost/assert.hpp>
# include <boost/pointer_cast.hpp>
# include <boost/shared_ptr.hpp>
using boost::shared_ptr;
using boost::static_pointer_cast;
using boost::dynamic_pointer_cast;

  class
base_type
  { public: virtual ~base_type( ) { } };

  class
derived_type
  : public base_type
  { };

  class
derived_type_other
  : public base_type
  { };

Notice base_type has a virtual destructor, which makes it a polymorphic class. A class has to have at least one virtual method if you want to use it with dynamic_pointer_cast<T>(..). Otherwise the compiler complains loudly.

Remember that, in general, declaring the destructors virtual is often not necessary if a class is being managed by shared_ptr<T>. If you always immediately attach a new target object to a shared_ptr< MOST_DERIVED_CLASS > after creation, then you don’t have to worry if shared_ptr< BASE_CLASS > later deletes that target object. The most-derived destructor is bound to the shared_ptr<T> during first attach and is passed along to subsequent shared and weak pointers.

Finally, here is the code showing static_pointer_cast<T>(..) and dynamic_pointer_cast<T>(..).

  // Make a shared_ptr to a new object.
  shared_ptr< derived_type >
sp_derived(
  new derived_type);

  // The shared_ptr knows how to upcast its
  // inner pointer.
  shared_ptr< base_type >
sp_base(
  sp_derived);

  // You can static-downcast the inner pointer.
  shared_ptr< derived_type >
sp_derived2(
  static_pointer_cast< derived_type >( sp_base));

  // You can dynamic-downcast the inner pointer
  // as long as the inner type is polymorphic.
  shared_ptr< derived_type >
sp_derived3(
  dynamic_pointer_cast< derived_type >( sp_base));
  BOOST_ASSERT( sp_derived3);

  // You can try to dynamic-downcast to the wrong type.
  // You will end up with a null shared_ptr because
  // the inner dynamic-downcast returns a zero pointer.
  // This does not throw std::bad_cast because it casts
  // pointers and not refs.
  shared_ptr< derived_type_other >
sp_derived_other(
  dynamic_pointer_cast< derived_type_other >( sp_base));
  BOOST_ASSERT( ! sp_derived_other);

Like const_pointer_cast<T>(..), static_pointer_cast<T>(..) and dynamic_pointer_cast<T>(..) also work with intrusive_ptr<T>s and raw pointers. But they don’t work with weak_ptr<T>, at least not in Boost 1_37_0 (I suspect it’s an oversight). They also do not work with shared_array<T>, which makes sense since array “pointers” should always be to the most-derived type, and of course they don’t work with the single-ownership smart pointers that don’t support normal copy semantics.

There is also a reinterpret_pointer_cast<T>(..) function, but it only works with raw pointers. Reinterpret cast is usually only used at a very low abstraction level, while smart pointers are highly abstracted. If you think you need a reinterpret cast with a smart pointer you are probably doing something wrong.

Comments

Leave a Reply