Spring 2024 CS 32

dynamic_cast

Suppose you decided to derive the Weapon class and the Scroll class from a base class GameObject. You've got an inventory of GameObject pointers, each of which points to a Weapon or Scroll, and you picked out one of those pointers. You want to see if it's pointing to a Scroll, and if so, you want to read that scroll. But now the trouble is, you've got a GameObject pointer and you need a Scroll pointer. (Presumably, GameObject does not have a read member function, since read doesn't make sense for GameObjects other than Scrolls.)

Consider this: You have a collection of Landmark pointers, each of which points to a Hotel, a Restaurant, a Library, etc. At the request of a hungry user, you want to visit every pointer in the collection, but display only the Restaurants and their food quality.

class Landmark {
  …
  virtual ~Landmark();	// Base classes should have a virtual dtor
  string name() const;
  …
};

class Restaurant : public Landmark
{
  …
  int foodQuality();
  …
};

class Library : public Landmark
{
  …
};

…
Landmark* lp;
…
lp = …;	// Set lp to point to a Restaurant or a Library object

How do we find out if lp really points to a Restaurant object? With dynamic_cast:

Restaurant* rp = dynamic_cast<Restaurant*>(lp);  // Try to convert lp
if (rp != nullptr)  // if result is not null, lp really points to a Restaurant
  cout << rp->name() << " has quality " << rp->foodQuality() << endl;
else  // null result means lp pointed to some other kind of landmark
  cout << lp->name() << " is not a restaurant" << endl;

Note: dynamic_cast does not copy the object pointed to; if it doesn't return a null pointer, it simply returns a pointer to the same object, but with the pointer being of the derived type.

Note: dynamic_cast only works for classes with at least one virtual function. A base class should always have a virtual destructor, so that's an easy requirement to meet.

Stylistic note: Don't overuse dynamic_cast. In most cases, when you have a base pointer, and you want to do different things depending on the kind of derived object it actually points to, just call a virtual function declared in the base class and implemented differently in the derived classes.