The main reason for the usage of them is to make polymorphism possible. Another technique that is needed for polymorphism is late/dynamic binding.
Upcasting allows us to use inherited classes (sub-classes) with the base class interface. You can handle those object with the same base class interface without need to know what concrete child class object it is.
On the other hand, downcasting is needed because you may want to get the special methods or member variables of a child object. Then, you need to downcast.
To cast up or down you can safely use the dynamic_cast
which is described here.
If the cast is successful, dynamic_cast returns a value of type new_type. If the cast fails and new_type is a pointer type, it returns a null pointer of that type. If the cast fails and new_type is a reference type, it throws an exception that matches a handler of type std::bad_cast.
To up or downcast between base and child class you need either a pointer (type*
) or a reference type (type&
) because only the view to the object changes not the concrete object itself. If you use the object itself object slicing would occur and you would lose information of an inherited class.
I give you one example when to use up- and downcasting. Consider you have a parent class Car
and 2 classes Porsche
and Ford
that are inherited from Car
. Now you have a std::vector<Car*> cars
for example where you want to put in different cars. You would do something like:
std::vector<Car*> cars;
cars.push_back(new Porsche()); /* implicit upcast */
cars.push_back(new Ford()); /* implicit upcast */
The benefit is you have one vector of "different" objects, it's possible because both have the same parent class.
If you now want to get those cars you can do:
Car* porscheAsCar = cars.at(0);
Porsche* porsche = dynamic_cast<Porsche*>(cars.at(0));
Now for example the Car
class does have a drive()
method and the Porsche
class a driveFast()
method implemented. You would access them:
porscheAsCar->drive(); /* Call Porsche drive() method */
porsche->drive(); /* Call Porsche drive() method */
porsche->driveFast(); /* Call Porsche driveFast() method */
Even though we call the drive
method with the base class interface it will be the drive
method of the Porsche
, if the method is declared with virtual. With the downcast you can access the methods/member variables that are specific for the inherited class. But it is just possible if the Car
is really a Porsche
and not a Ford
for example.
Full example with some output on ideone see here.