开发者

Casting a pointer to a sub-class (C++)

开发者 https://www.devze.com 2022-12-13 03:28 出处:网络
I\'m developing a game and I need to find a way of getting the value of a certain \'map block\' in the game (in char format). I have a class DisplayableObject which takes care of all sprites, and a su

I'm developing a game and I need to find a way of getting the value of a certain 'map block' in the game (in char format). I have a class DisplayableObject which takes care of all sprites, and a sub-class ThreeDCubePlayer which takes care of the player object. For ease of rendering/updating everything, all DisplayableObjects are stored in an array, with the 0th cell containing the player (which is of type ThreeDCubePlayer). ThreeDCubePlayer has a different constructor from DisplayableObject (it takes two additional arguments) and only ThreeDCubePlayer has the GetMap() functions that I need. So, here is what I have done so far:

ThreeDCubePlayer* cubePlayer = &((ThreeDCubePlayer &)m_ppDisplayableObjects[0]);

char mapEntry = GetMapEntry((int)*(cubePlayer->GetMapX()), (int)*(cubePlayer->GetMapY()));

This is the part of ThreeDCubeGame.cpp (the function which controls the map and keyboard input). The problem I've had is that both of these lines give an 'illegal indirection' error at compilation. I thought this error is when I try to dereference something that isn't a pointer, and I'm sure cubePlayer looks like a pointer...

Does anyone 开发者_运维问答have an idea as to what I should do?


Use one of the type safe casts, e.g. dynamic_cast instead of the C-style cast.

If m_ppDisplayableObjects is a DisplayableObject**, then it would look something like this:

ThreeDCubePlayer* cubePlayer = dynamic_cast<ThreeDCubePlayer*>(m_ppDisplayableObjects[0]);

if (cubePlayer != NULL)
{
    char mapEntry = GetMapEntry(cubePlayer->GetMapX(), cubePlayer->GetMapY());
}
else // Not a ThreeDCubePlayer* ...


A couple of suggestions:

Don't use the C-style casts, use proper C++ casts instead. In your case, as you're casting down the inheritance hierarchy, you should be using dynamic_cast instead of the sledgehammer C-style cast. This will incur a small runtime overhead but it'll also make the whole thing type safe inasmuch as it isn't going to do something nasty behind your back simply because you're treating a chunk of $deity_knows_what as a ThreeDCubePlayer. Assuming that your m_ppDisplayableObjects array actually holds pointers, it'll look like this:

ThreeDCubePlayer *cubePlayer = dynamic_Cast<ThreeDCubePlayer *>(m_ppDisplayableObjects[0])
if (cubePlayer) {  // Important, if you don't check for 0 here you might dereference a null pointer
   ... cubePlayer->GetMapX() ...

Also, if you have to cast the result of the GetMapX then you have an impedance mismatch that you should sort out somewhere else; I'd recommend either adjusting the return type of GetMapX or the parameters passed to GetMapEntry. Usually, having to wildly cast about is a sign of a design issue - well-designed C++ code should not require a lot of casts and especially not a lot of C-style casts.


Your cast is wrong, and I think the second line requires no cast at all (depends on how the methods are defined).

It should be:

ThreeDCubePlayer* cubePlayer = (ThreeDCubePlayer*)m_ppDisplayableObjects[0];

char mapEntry = GetMapEntry( cubePlayer->GetMapX(), cubePlayer->GetMapY() );

The cast in the first line should also be a C++ style cast, e.g.:

ThreeDCubePlayer* cubePlayer = static_cast<ThreeDCubePlayer*>(m_ppDisplayableObjects[0]);


Be aware that in a game application, having a situation where you end up doing zillions of dynamic_casts per game frame can negatively impact performance. You'll usually find people doing other solutions to determine how to recast a object pointer stored in a container to the appropriate object type using static_cast or C style casting rather than relying on RTTI. Depending on the number of object types and other factors, there are various ways of doing this, but a simple method is just to have a enum class id and a get method for each of the enum types that returns null if the class id doesn't match the one being requested.


For the first line, you can cast the DisplayableObject to the derived class ThreeDCubePlayer type using dynamic_cast.

ThreeDCubePlayer* cubePlayer = dynamic_cast<ThreeDCubePlayer*> (m_ppDisplayableObjects[0]);

For the second line, you're dereferencing whatever is returned by ThreeDCubePlayer::GetMapX(). If that function doesn't return a pointer (or some class with an overloaded * operator), you'll get a compilation error.


You haven't given much code to go on, but I think your first line should be:

ThreeDCubePlayer* cubePlayer = (ThreeDCubePlayer *) m_ppDisplayableObjects[0]);

We'd need to see the declaration of GetMapX() to know about the second line.


ppDisplayableObjects is an array or base pointers isn't it? so try this?

const ThreeDCubePlayer* const cubePlayer = m_ppDisplayableObjects[0]; 
char mapEntry = GetMapEntry( cubePlayer->GetMapX(), cubePlayer->GetMapY() );

GetMapX etc. ought to return an (unsigned) int? and not a pointer to an int? (no negs? so unsigned?)

I'd like to second everyone else's comments on casting, they're a sign that your hierachy is not working quite right, but... but if you do have to cast then thinking about which C++ cast you'd need to use is a useful exercise, it also means when you want to revisit/tighten up your code all the casts are easier to search out and remove

ps - rack up your constness too where you can and add the arrays etc to some sort of owner class, maybe a singleton if you know you've only got the one

also IMHO... (sorry) write yourself a Coords class so that you can do things like GetMapEntry(const Coords& coords) instead of getting the x and the y values separately, this'll save you getting them swapped round the wrong way etc. :)

0

精彩评论

暂无评论...
验证码 换一张
取 消