1

So I have a class hierarchy that essentially has Entity class as the parent abstract class and a bunch of other classes that derive from it, such as Door, Player, Ground, etc.

I also have a three-dimensional vector that stores the pointers to objects of type Entity and I fill up this vector with the derived objects. Within the Door class I have a method called isOpen() that simply returns a bool. This function is specific to the Door class and is neither found in Entity class nor in any other derivations of it (as I don't need to check whether, for example, a Ground object is open or not).

Now, knowing that there exists an object of type Door at vector position i, j, k, I would like to call the method isOpen like so: vector[i][j][k]->isOpen(). Unfortunately, when I do this, the compiler returns class Entity has no member named isOpen(). This is understandable since the function isOpen() is exclusive to the Door class, but what can I do in order to make this sort of call possible?

jxh
  • 69,070
  • 8
  • 110
  • 193
Nonomus
  • 127
  • 1
  • 9
  • 1
    Don't just *tell* us about your code; ***showing*** it is *much* more productive. Second, [`dynamic_cast<>`](http://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-and-reinterpret-cast-be-used) might be of some use to you. Don't just throw it in, read about how to use it **first**. – WhozCraig Aug 19 '13 at 21:06

3 Answers3

2

Short answer:

Cast the Entity down to a door: static_cast<Door*>(vector[i][j][k])->isOpen().

Long answer:

Your design isn't proper if you need to know a specific derived type is at a specific location. Fixing this might be as simple as moving the isOpen() function up to Entity with a default implementation returning true. Or it could require a whole rethinking of the code that works with the members of vector.

John
  • 7,301
  • 2
  • 16
  • 23
  • 4
    If the entity being pointed to is *not* in fact a `Door` or a derivation of `Door` further down the hierarchy, this is **undefined behavior** and will most-assuredly crash. `static_cast<>` is *not* the casting type to use here. See its description [in this question and answer](http://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-and-reinterpret-cast-be-used) for why. – WhozCraig Aug 19 '13 at 21:12
  • You would want to use `reinterpret_cast`, not `static_cast` - though that method is NOT a recommended approach. The long answer is more on track - fix the design. – Zac Howland Aug 19 '13 at 21:16
  • Ah, thanks for the suggesting to use a type cast. In terms of the class redesign, do you have any suggestions as to how I would go about doing that? It seems that a vector with multiple objects of the same parent class is integral to my program :( – Nonomus Aug 19 '13 at 21:20
  • 1
    Is dynamic_cast with a null check not more appropriate ? The design does sound a bit flawed. Not sure about moving IsOpen to the base class though, as IsOpen does not sound applicable to every type. Rethinking the entire approach is the way to go I think. – Kindread Aug 19 '13 at 21:20
  • @Kindread it is *much* more appropriate to use `dynamic_cast<>` for this and check it for NULL before firing the method. You're correct. – WhozCraig Aug 19 '13 at 21:22
  • Not being one to avoid specifics, the *specific* confines of this question make this answer plausible. The OP specifically said he *knew* there was a `Door*` at `[i][j][k]`, and as such, a static cast *will* work and cause no ill-effects. Were it *unknown* and not a `Door*` the compiler would happily encode a call to `Door::isOpen` passing a non-`Door*` as `this`. The call grabs a value from memory where it thinks the `bool` behind `isOpen()` resides, and if you're lucky, *not* fault. But as I said, the OP says he "knows" its a `Door*`. Therefore, it works, but `dynamic_cast<>` is "right" imo. – WhozCraig Aug 20 '13 at 03:00
2

Consider polymorphic casting as supported by the language using dynamic_cast<> For references it will throw an exception (std::bad_cast) but for pointers if the target type is not compatible it will simply return NULL, so... assuming your base class and its derivations are indeed polymorphic (i.e. at least one virtual method):

Door* pDoor = dynamic_cast<Door*>(vector[i][j][k]);
if (pDoor)
    pDoor->isOpen();

Comments about the design withheld. Opinions are like... yeah. everyone has one.

WhozCraig
  • 65,258
  • 11
  • 75
  • 141
2

One way to solve this is with a down cast to a Door * first. However, in order for this down cast to be type safe, you should use dynamic_cast<Door *>(). If Entity does not already have a virtual method, you can add a virtual destructor.

class Entity {
    //...
    virtual ~Entity () {}
};

void foo (Entity *e) {
    //...
    Door *door = dynamic_cast<Door *>(e);
    if (door) {
        if (door->isOpen()) {
            //...
        }
    }
    //...
}
jxh
  • 69,070
  • 8
  • 110
  • 193