In my example:
At upcasting, shouldn't the second d.print()
call print "base"?
Isn't it "d" derived object upcasted to a base class object?
And at downcasting, what advantages does it have?
Could you explain upcast and downcast in a practical way?
#include <iostream>
using namespace std;
class Base {
public:
void print() { cout << "base" << endl; }
};
class Derived :public Base{
public:
void print() { cout << "derived" << endl; }
};
void main()
{
// Upcasting
Base *pBase;
Derived d;
d.print();
pBase = &d;
d.print();
// Downcasting
Derived *pDerived;
Base *b;
pDerived = (Derived*)b;
}
Upcasting can cause object slicing when a derived class object is passed by value as a base class object, as in foo(Base derived_obj). Downcasting. The opposite process, converting a base-class pointer (reference) to a derived-class pointer (reference) is called downcasting.
Upcasting (Generalization or Widening) is casting to a parent type in simple words casting individual type to one common type is called upcasting while downcasting (specialization or narrowing) is casting to a child type or casting common type to individual type.
In Upcasting a child object is typecast to a parent object. On the other hand, the reference of the parent class object ends up passing on to the child class when it comes to downcasting.
Upcasting is safe casting as compare to downcasting. It allows the public inheritance that implicitly cast the reference from one class to another without an explicit typecast. By default, the upcasting create is-a relationship between the base and derived classes.
Up-casting is implicit in C++, and is used a lot when you deal with virtual dispatching. In other words, you have a pointer to Base
from which you can access the common interface of a whole hierarchy of classes, and the selection can be done at runtime. This assumes that your interface functions are marked virtual
. Example:
Base* pBase;
cin >> x;
if(x == 0) // this is done at runtime, as we don't know x at compile time
pBase = new Derived1;
else
pBase = new Derived2;
pBase->draw(); // draw is a virtual member function
It is extremely useful in these situations in which the dispatch is done at runtime. Simply said, upcasting allows one to treat a derived class as a base class (via its common interface).
Down-casting is less useful, and IMO should be avoided whenever one can. In general is a sign of bad design, as one rarely needs to convert a Base
object to a derived one. It can be done (and the result checked) via dynamic_cast
, like
Base* pBase = new Derived; // OK, the dynamic type of pBase is Derived
Derived* pDerived = dynamic_cast<Derived*>(pBase);
if(pDerived) // always test
{
// success
}
else
{
// fail to down-cast
}
This link provides a quite useful intro to the subject.
You need to use virtual methods in order to enable RTTI.
In your case, since you are using C++, you should rely on safer casting mechanisms. So, instead of (Derived*)b
, you should be using dynamic_cast<Derived*>(b)
. This allows you to make sure that you are actually in possession of a pointer to an object to a base class (interface) that was obtained by casting up an object of type Derived
. This page provides further explanations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With