1

I read the description about upcasting and downcasting from http://www.studytonight.com/cpp/upcasting.php:

[...] the act of converting a Sub class's reference or pointer into its Super class's reference or pointer is called Upcasting. The opposite of Upcasting is Downcasting, in which we convert Super class's reference or pointer into derived class's reference or pointer. We will study more about Downcasting later.

But I do not understand why upcasting and downcasting are used in C++. Can you give an explanation about why these mechanisms are used?

Andre Kampling
  • 5,476
  • 2
  • 20
  • 47
Sunny Lei
  • 181
  • 1
  • 3
  • 15

3 Answers3

4

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.

F14
  • 67
  • 2
  • 6
Andre Kampling
  • 5,476
  • 2
  • 20
  • 47
2

When have a base class, from which several classes inherit, we often want a pointer that can point to one of those derived classes.

For example we can have an Animal class and derived Dog and Cat classes:

class Animal {};

class Dog : public Animal {};
class Cat : public Animal {};

Dog dog;
Animal* a = &dog;

Cat cat;
Animal* b = &cat;

Often times, we want to have a pointer that can pointer to one of these objects. We can use an Animal pointer, since both a Dog and a Cat are a type of Animal. This is the nature of upcast. We upcast a derived class and represent it as the base class.

What about downcasting? We can do so using a dynamic_cast:

Cat c;
Animal* animal = &c; //Implicit upcast
Cat* cat = dynamic_cast<Cat*>(animal); //Explicit downcast
//Check if dynamic cast worked:
if(!cat) {
    //ERROR: Not a cat object
}
  • You can use a Dog dog object directly, but it is better to use a pointer, since the base object will be preserved. Upcasting a value object like in the expression `Dog dog; Animal a = dog;` will cause the object to be "sliced" hence the term "object slicing." – D. Christopher Jul 14 '17 at 13:54
  • Thanks! Why do not use dog pointer " Dog star dog" directly? I try to put a star notation between Dog and dog, but it cannot be displayed... – Sunny Lei Jul 14 '17 at 14:10
  • @SunnyLei a pointer needs to point to something. If you just have a `Dog* dog` with nothing to point to you don't have an object. `Dog dog` is an object you can use directly. – Kevin Jul 14 '17 at 14:14
  • The point of using Animal pointer is to have a pointer that can point to multiple different types. We can have an array of Animal pointers and can assign Dog and Cat pointers to all of them. Then we can use dynamic_cast to downcast the pointer of the actual object and work with it. This allows us to create new types that inherit from Animal and allow them to be assigned to the same base Animal pointer. We can even have function which can take an Animal pointer as an argument instead of having multiple functions with different pointer/reference arguments. – D. Christopher Jul 14 '17 at 14:19
0

In my humble opinion, the website you are using is of a poor quality. I've tried to read some article: they are not incorrect but they are not even suitable for who is trying to enter in the C++ world with a little programming experience. Even I, with my little 15 years experience as professional C++ programmer, found it a little bit stressful to read.

As someone said a good book, even free, it's a better solution. Google is your best friend for search. That's a good answer to your question, more complete than whatever I could write: https://www.tutorialcup.com/cplusplus/upcasting-downcasting.htm

Have a nice day, Ste.

Stefano Buora
  • 1,052
  • 6
  • 12