Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

downcasting with dynamic_cast 6

Status
Not open for further replies.

titanandrews

Programmer
Feb 27, 2003
130
US
Hello,
I understand with C++, I have the ability to downcast an object using dynamic_cast, although probably not something that is done too often. (Someone please correct me if I'm wrong) I created this little example here to help me understand what I can do with this operator, but I am having a problem on downcast. I get a mem-ref error because myOffice_ptr is NULL. It should be a valid cast because the bad_cast exception never gets thrown. I compiled with the option /GR to enable RTTI. (Something my book tells me to do, although I don't know what RTTI is.) Can anyone please tell me what is wrong? Any other information you want to provide on dynamic_cast is also appreciated. Thanks!

Barry


Code:
#include <iostream>
#include <cstdlib>
using namespace std;

class Room
{
public:
    virtual void cleanIt()
    {
        cout << &quot;Cleaning the Room &quot; << endl;
    }

    virtual Room::~Room()
    {

    }
};

class Office : public Room
{
public:
    void cleanIt() 
    {
        cout << &quot;Cleaning the Office &quot; << endl;
    }
};

class Garage : public Room
{
public:
    virtual void cleanIt() 
    {
        cout << &quot;Cleaning the Garage &quot; << endl;
    }
};

int main(int argc, char *argv[])
{
    Garage *myGarage_ptr = new Garage;
    myGarage_ptr->cleanIt();

    //Garage to Garage. No problem.
    Garage *anotherGarage_ptr = dynamic_cast<Garage *>(myGarage_ptr);
    anotherGarage_ptr->cleanIt();
    delete myGarage_ptr;

    //Garage to Room. No problem.
    Room *myRoom = dynamic_cast<Room *>(anotherGarage_ptr);
    myRoom->cleanIt();    

    Room *anotherRoom_ptr = new Room;
    anotherRoom_ptr->cleanIt();

    try
    {    
        Office *myOffice_ptr = dynamic_cast<Office *>(anotherRoom_ptr);
        myOffice_ptr->cleanIt();//Failure here because myOffice_ptr is NULL.
    }
    catch (bad_cast &)
    {
        cout << &quot;Bad cast &quot; << endl;
    }

    
    //Illegal. Will compile with warning, but fail at runtime because Office cannot be a Garage.
    //Office *myOffice = dynamic_cast<Office *>(anotherGarage_ptr);

}
 
You cannot dynamic_cast a Room to an Office (This would be 'upcasting' I guess. The opposite is possible).
It's like saying that a Car is a Ferrari : Wrong even though a Ferrari certainly is a car.

Don't know about bad_cast - I allways check for a null-pointer.

RTTI is runtime type information.

/JOlesen
 
Then maybe it's possible my book could be wrong. It specifically says, &quot;The dynamic_cast operator can be used to change a pointer or reference to a base class to that of the derived class and vice versa.&quot; Very confusing if that's not true.



Barry
 
I am a bit confused, but maybe because I am bad at OOP. If a Ferrari inherits every characteristic of a car, when would you need to change a pointer's type so that it thinks a Ferrari is a mere car? You already have access to all the car features (and more), without changing the pointer, don't you?
But I can see that &quot;up-casting&quot; couldn't work. If you have a car and you suddenly declare that you want to treat it as a Ferrari, then your user may issue an instruction to wind down the electric windows, where what they are actually dealing with is a 1960's mini with no such luxuries... In computing terms sounds like a call to a function that doesn't exist, a sure trip to oblivion.
 
If you have a 'Car' pointer that points to an object created with this stmt :
Car * p = new Ferrari;

This pointer could be dynamic_cast'ed to a Ferrari, because the type *is* a Ferrari.

This pointer cannot be dynamic_cast'ed to a Ferrari :
Car * p = new Toyota

/JOlesen
 
Look at the inheritance diagram for your classes. There is no connection between Garage and Office B-)
Code:
        <Room>
         /           /            /         <Garage>   <Office>

Also the Room class should be abstract so that you cannot create a Room object and try to upcast it to a concrete class.

Now with all that said it is perfectly legal, but not necessarily a good design, to do this:
Code:
Room* ptr = new Garage();

Garage* pGarage = dynamic_cast<Garage*>(ptr);

In most cases finding that you need to upcast suggests a design flaw.

-pete
 
Thanks guys for your help! All this is much more clear to me now. Just one more question along the same lines. Could someone please clarify upcasting/downcasting? If I have a hierarchy like this:
<Room>​
/ \​
<Garage> <Office>​

It seems like downcasting would be casting Room to Garage (down the hierarchy) and upcasting would be casting Garage to Room (up the hierarchy), but looking at these posts the opposite is true??


thanks,

Barry
 
P.S. Also in my example, if casting Room to Office is not valid (and I see now that it's not), why is the bad_cast exception not thrown?


Barry
 
Upcast to the most derived class
Downcast to the least derived class

>> why is the bad_cast exception not thrown?

I have not used dynamic_cast() for a while, but I believe it only throws the exception for reference types. For pointer types it will return NULL which you must check for.


-pete
 
lionelhill,

Downcasting can be quite handy, for instance:

Suppose you've got an array of pointers to a plain CAR object. You might own a green MINI, a red FERRARI and a blue JAGUAR (all derived of CAR, of course....). All of a sudden, for whatever reason, you decide that you want to have them all painted yellow.

Now, if color is a property of the plain CAR class, you're right that you can access that property from FERRARI, MINI and JAGUAR. However, you can't access MINI from JAGUAR etc. But, since you've got an array of downcasted pointers, you can still loop through that array to change all colors at once.

Also think about overridden methods in the derived classes which, for example, can render a photo of your precious car by just looping through the array of downcasted pointers.


Just a very simple example of why it can be easy to use downcasted pointers.....

Greetings,
Rick
 
The confusion on up/down casting stems from the way people draw the diagrams. It can be drawn as
Code:
      <room>                  <room>
      ^    ^                  |   |
      |    |                  v   v
<garage>  <office>      <garage> <office>
It depends on whether you are used to UML, Booch, Ramabaugh (have I spelt this correctly?) or Shlaer-Mellor. Some have arrows pointing from the base to the derived, others have it in the opposite direction.
 
You all had a very good discussion. But I would like to add up a few points here.

Explicit upcasting isn't needed at all. YOu can do it implicitly. Say,

Garage* pGarage = new Garage();
Room* pRoom = pGarage; // No dynamic_cast needed here.

Moreover, Siblings won't be able to do the dynamic_cast. So dynamic cast between Garage and Office fails.
Hope this helps!

 
I'm not sure about this, but I think the advantage of them dynamic_casts is checking if the cast actually can be done (i.e. if the oject to cast to is actually part of the hierarchie of the source object, a null pointer will be returned if not).

I might be wrong though, since I never use dynamic_casts...

Greetings,
Rick
 
Dynamic_cast supports casting to a sibling class however, the class must be polymorphic. Office contains a the member function
void clean_it()
which is not virtual and therefore not polymorphic. So the dynamic_cast returns a zero as it rightly should. Correct me if this is a typo and the member function is virtual
 
Titan,

There are no errors here. The job of dynamic_cast is to return NULL when it identifies an object is not the target type.

Run-time type information (rtti) is hierarchy and class name information available for analysis at runtime. With rtti enabled, you can ask an otherwise lost pointer 'what is your name?' and 'who are your parents?'.

==Rich Frank
ExtraLogoIconText.bmp
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top