6

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;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mihai
  • 101
  • 2
  • 2
  • 8
  • 2
    Why do you think the `pBase` line should change the behaviour of `d.print();` ? Did you mean to ask about `pBase->print();` ? – M.M Feb 01 '16 at 02:14

3 Answers3

17

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.

vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • So the code lines : "pBase = new Derived1;" and "pBase = new Derived2;" represent actually upcasting ? If so , let's assume x is 0 and pBase will point to an object of "Derived1" class . What would be the difference if pBase pointer would be "Derived1 *pBase " ? – Mihai Jan 30 '16 at 13:17
  • @Mihai It's useful whenever you don't know in advance the derived type. In that case you use the pointer to base to control the derived hierarchy. – vsoftco Jan 30 '16 at 13:18
  • Down-casting is bad design? That is an insane point to make! It's up-casting that's bad design since it leads to undefined behaviour that is unkown at compile-time and unpredictable at run-time. It's actually the down-casting example that provides a solid foundation of work. – Poriferous Jan 30 '16 at 13:18
  • `dynamic_cast` should be `dynamic_cast`. – Mihai Todor Jan 30 '16 at 13:18
  • 2
    @Poriferous I hope you realize that `Base* p = new Derived` is (implicit) upcasting, not downcasting. Upcasting is used way more than downcasting. Again, IMO, `dynamic_cast` should be used sparsely. – vsoftco Jan 30 '16 at 13:19
  • Imo, it's `static_cast` that needs to be used sparsely. `dynamic_cast` is used a lot and provides a safe way to convert from one type to another. When it comes to casting a base to a derived, it's there to use specific functions of that derived which otherwise would bloat or disrupt the base interface. Maybe you're looking at things too generically or viewing the design from a technical POV rather than philosophical one. – Poriferous Jan 30 '16 at 13:22
  • 1
    @Poriferous I agree one should not `static_cast` on dynamic types. Upcasting is implicit though, it's just about controlling the interface of a class hierarchy via a base pointer. And this is important IMO. – vsoftco Jan 30 '16 at 13:27
  • By the way, the OP did not make use of virtual methods, which will not allow him to make use of virtual dispatching. – Mihai Todor Jan 30 '16 at 13:30
  • As an addendum, there are some situations where downcasting is a perfectly valid choice, rather than bad design. These are primarily cases where the actual type is known upon use (and typically intended to allow access to the full interface (if applicable), rather than only the shared portion), or hidden within the class itself. The former may come up when an object has to be passed through code that doesn't need to know its actual type between creation and consumption, and the latter allows the base to check compatibility before dispatching (e.g., for polymorphic comparison operators). – Justin Time - Reinstate Monica Sep 19 '19 at 14:42
8

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.

Mihai Todor
  • 8,014
  • 9
  • 49
  • 86
  • I am not downvoter (maybe I should..) but your answer is pretty good asnwer but not to this very question above - I guess this is the reason. – PiotrNycz Apr 10 '18 at 12:35
  • Well, to my defence, the question wasn’t all that great either. Please let me know how you think I should improve my answer. – Mihai Todor Apr 10 '18 at 18:28
1

If you want to call print "Base", you should do it like this; here, we are upcasting a derived class object to this base class object, so, when we call pBase->print(), it goes to base class and calls it; but, if the print function is virtual, it will call the derived class, becoase it is overriding this function in the derived class.

void main(){
    // Upcasting
    Base *pBase;
    Derived d;
    d.print();
    pBase = &d;
    pBase->print();
}
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83