Die Boost C++ Bibliotheken

Kapitel 54. Boost.Conversion

Die Bibliothek Boost.Conversion bietet in der Headerdatei boost/cast.hpp die zwei Cast-Operatoren boost::polymorphic_cast und boost::polymorphic_downcast an. Sinn und Zweck dieser Cast-Operatoren ist es, eine dynamische Typumwandlung, die normalerweise mit dynamic_cast erfolgt, zu präzisieren.

Beispiel 54.1. Down- und Crosscasts mit dynamic_cast
struct base1 { virtual ~base1() = default; };
struct base2 { virtual ~base2() = default; };
struct derived : public base1, public base2 {};

void downcast(base1 *b1)
{
  derived *d = dynamic_cast<derived*>(b1);
}

void crosscast(base1 *b1)
{
  base2 *b2 = dynamic_cast<base2*>(b1);
}

int main()
{
  derived *d = new derived;
  downcast(d);

  base1 *b1 = new derived;
  crosscast(b1);
}

Im Beispiel 54.1 wird der Cast-Operator dynamic_cast zweimal eingesetzt: In der Funktion downcast() wandelt er den Zeiger auf eine Elternklasse in den Zeiger auf eine Kindklasse um. In der Funktion crosscast() wandelt er den Zeiger auf eine Elternklasse in einen Zeiger auf eine andere Elternklasse um. Die erste Umwandlung wird als Downcast bezeichnet, die zweite Umwandlung als Crosscast.

Indem die Cast-Operatoren von Boost.Conversion eingesetzt werden, kann wie im Beispiel 54.2 ein Downcast von einem Crosscast im Code unterschieden werden.

Beispiel 54.2. Down- und Crosscasts mit polymorphic_downcast und polymorphic_cast
#include <boost/cast.hpp>

struct base1 { virtual ~base1() = default; };
struct base2 { virtual ~base2() = default; };
struct derived : public base1, public base2 {};

void downcast(base1 *b1)
{
  derived *d = boost::polymorphic_downcast<derived*>(b1);
}

void crosscast(base1 *b1)
{
  base2 *b2 = boost::polymorphic_cast<base2*>(b1);
}

int main()
{
  derived *d = new derived;
  downcast(d);

  base1 *b1 = new derived;
  crosscast(b1);
}

Der Cast-Operator boost::polymorphic_downcast kann nur für Downcasts verwendet werden. Er verwendet intern static_cast, um die Umwandlung durchzuführen. Da static_cast nicht dynamisch überprüft, ob die Typumwandlung gültig ist, darf boost::polymorphic_downcast nur angewandt werden, wenn sicher ist, dass die Typumwandlung durchgeführt werden darf. Zur Kontrolle greift boost::polymorphic_downcast in Debug-Versionen auf dynamic_cast zu und überprüft mit assert(), ob die Typumwandlung erfolgen darf. Diese Überprüfung findet jedoch nur statt, wenn das Makro NDEBUG nicht definiert ist, was üblicherweise nur in Debug-Versionen der Fall ist.

Während mit boost::polymorphic_downcast ein Downcast möglich ist, muss boost::polymorphic_cast für einen Crosscast verwendet werden. Dieser Cast-Operator verwendet intern dynamic_cast, da dies der einzige Cast-Operator ist, der tatsächlich einen Crosscast durchführen kann. Der Vorteil von boost::polymorphic_cast gegenüber dynamic_cast ist, dass boost::polymorphic_cast im Fehlerfall eine Ausnahme vom Typ std::bad_cast wirft. dynamic_cast hingegen gibt einen Nullzeiger zurück, wenn die Typumwandlung fehlschlägt. Anstatt den Rückgabewert selbst auf einen Nullzeiger zu überprüfen, wird die Überprüfung von boost::polymorphic_cast abgenommen.

Beide Cast-Operatoren boost::polymorphic_downcast und boost::polymorphic_cast können nur verwendet werden, wenn Zeiger umgewandelt werden müssen. Ansonsten muss auf dynamic_cast zugegriffen werden. So kann boost::polymorphic_downcast, das auf static_cast basiert, Objekte vom Typ einer Elternklasse nicht in Objekte vom Typ einer Kindklasse umwandeln. Es ergibt außerdem keinen Sinn, boost::polymorphic_cast einzusetzen, wenn andere Typen als Zeiger umgewandelt werden sollen, weil dynamic_cast bei einer derartigen Umwandlung im Fehlerfall selbst eine Ausnahme vom Typ std::bad_cast wirft.