Casting Pointer to Derived Type

Started by
23 comments, last by SmkViper 9 years, 5 months ago

Eh, this may be kinda stupid, but I have the traditional setup:


class tile {
    // ...
};

class tilePlayer : public tile {
    // ...
};

At one point in my code I had a pointer to a tile instance and I wanted to access it as a tilePlayer instance. So I tried something like this:


// map is an array of pointers to tile instances
(tilePlayer*)map[ index ]->PlayerSpecificFunction();

This didn't compile ( "PlayerSpecifcFunction not member of tile" ) so I tried this and it worked:


tilePlayer* p = (tilePlayer*)map[ index ];
p->PlayerSpecificFunction();

Isn't the latter just the same as the former but with more steps? Or am I messing up the syntax?

Advertisement

Your cast binds to the wrong expression:

(tilePlayer*)map[ index ]->PlayerSpecificFunction();

is equivalent to

(tilePlayer*)(map[ index ]->PlayerSpecificFunction());

whereas you want

((tilePlayer*)map[ index ])->PlayerSpecificFunction();

That's another reason to not use C-style casts and use the more explicit C++ style casts, because you cannot get the cast to bind to the wrong expression by accident.

static_cast<tilePlayer*>(map[ index ])->PlayerSpecificFunction();

Gah, that was stupid. Thanks.

That's another reason to not use C-style casts and use the more explicit C++ style casts, because you cannot get the cast to bind to the wrong expression by accident.

Thanks for the tip! I'll upgrade my casts.

Some unrelated points:

* Casting is usually a sign of a mismatch between your code design and your inheritance hierarchy

* Are you sure a player "is-a" tile?

One alternative implementation is that a tile has a pointer to any player that happen's to occupy it, or nullptr if there is no such player. Alternative implementations might decouple the player from the tile by just storing the tile index that the player is "on" (assuming your game has a tile based map that the player moves across).

Also - if you absolutely have to down-cast (and you usually don't, C++ provides a lot of mechanisms to avoid it), then you should use dynamic_cast, not static_cast. dynamic_cast will use RTTI to ensure that the pointer actually is what you think it is and return nullptr otherwise. This way you'll crash immediately trying to access a nullptr value rather then reading/writing random memory.
Personally I would probably aim to use something like boost::polymorphic_downcast in such a situation.

If some part of your code has a pointer to a tile and it needs to know the specific type of tile it is, I think there is something wrong with your design.

As rip-off said, are you sure the player is a tile? A tile simulator -where you can experience the excitement of being glued to the floor- seems like an odd premise for a game. :P

Also - if you absolutely have to down-cast (and you usually don't, C++ provides a lot of mechanisms to avoid it) [...]

Could someone please elaborate on this?

The need to cast to a subclass type arises all the time in well-designed architectures. Please stop it with the scaremongering about downcasting being a symptom of bad design. It's not. If you want to eliminate it everywhere, then your code is going to turn to shit because you'll be jumping through all kinds of unnecessary hoops like adding lots of virtual functions to do simple things.

As a basic example, consider a GUI system in which there is a class hierarchy of widgets. Suppose there is a resource format of some kind that stores all the widgets for a dialog box, and suppose that when it's loaded, the widgets of the appropriate subclasses (TextWidget, ButtonWidget, MenuWidget, etc.) are created and stored in a tree representing the layout of the dialog. Now some code is going to load that resource and want to access particular widgets as their specific subclass types, e.g., to change the content of a TextWidget to the user's name or enable/disable a ButtonWidget depending on some condition. However, the function that locates those particular widgets (perhaps by name or some kind of ID number) after the dialog is loaded will always return a pointer to the Widget base class. Knowing what the widget's actual subclass type must be, your program will then use static_cast to change a Widget * into a pointer to a TextWidget *, ButtonWidget *, etc., so it can call the functions specific to those subclasses. There's nothing wrong with this.

Then why did you feel the need to downvote me? The huge advantage of boost::polymorphic_downcast is that it verifies the type in debug builds (always a good idea to assert things which should be true there) and is a static_cast in non-debug builds.

This topic is closed to new replies.

Advertisement