2

So presume I have a base class Object and an abstract base class Collidable. (Object containing position information and such and Collidable containing virtual void Collide(Object object) = 0. There will then be child classes that inherit Object, but only certain ones will also inherit Collidable. So my question is, if one of those collidable child classes were to check through a list of Object inherited classes, how might it determine if they also inherit Collidable so that they collide with each other and not with objects that aren't collidable?

(To give a more visual look at my question)

class Object
{
protected:
    Position myPosition;

public:
    Object(void);
    ~Object(void);
}

class Collidable
{
protected:
/* ... */

public:
    virtual void Collide(Object& object) = 0;

    Collidable(void);
    ~Collidable(void);
}

class Grass : public Object
{
private:
/* ... */

public:

    Grass(void);
    ~Grass(void);
}

class Wall : public Object, public Collidable
{
private:
/* ... */

public:
    virtual void Collide(Object& object) { /* Collide logic */ }

    Wall(void);
    ~Wall(void);
}

class Monster : public Object, public Collidable
{
private:
/* ... */

public:
    virtual void Collide(Object& object) { /* Collide logic */ }

    Monster(void);
    ~Monster(void);
}

int main()
{
    Monster creature;
    Object* objects[] = { /* list of Grass, Wall, and Monster classes */ };

    for(int i = 0, i < objects.size(); i++)
    {
        //Logical error: not every object is collidable
        creature.Collide(&objects[i]);
    }
}

So here, I have a list of Wall Monster and Grass classes, but Grass is not collidable, however, let's say that it needs to stay in the array with the other classes. How might I determine if the class in the array is Collidable?

( I do apologize if I am somehow way off key here, but I have been researching and studying a bunch of object oriented things recently so I am still in my learning phase here. )

Uulamock
  • 330
  • 1
  • 3
  • 15
  • 1
    probably a terrible suggestion, but you could add a isCollidable() virtual method to Object, which has a default implementation that returns false. Then, on your subclasses that also inherit Collidable, override isCollidable() to return true. Then you can just check at runtime. – bstar55 Jun 06 '14 at 18:29
  • 1
    I recommend looking up how to implement Component systems. Some helpful links are: http://gamedev.stackexchange.com/questions/75721/how-should-an-object-that-uses-composition-set-its-composed-components and http://gameprogrammingpatterns.com/component.html and http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/ – Casey Jun 06 '14 at 20:09
  • @bstar55 - That isn't a horrible idea, it is a much better idea than what I am trying to do in this question of mine. – Uulamock Jun 06 '14 at 23:44
  • @Casey - Thanks for the links, I will certainly look them over, I will take all the help I can get. – Uulamock Jun 06 '14 at 23:45

2 Answers2

3

(Note: Some advice especially if you're in the learning phase - if you make sure your example code compiles some baseline, it makes it easier for people to adapt a working version for the part you are asking about. The compiler warnings are also instructive so you can find out about mistakes ahead of time... for instance you're missing a virtual destructor on Object. It can be a distraction if we don't know whether you know why that's bad or not.)


You're trying to encode attributes into objects by virtue of what classes they inherit from, and then check for those attributes at runtime.

It is technically possible to use Run-Time-Type-Information, use a dynamic_cast<> and notice when it returns a null pointer.

Grass grass;
cout << dynamic_cast<Collidable *>(&grass) << "\n";

Monster monster;
cout << dynamic_cast<Collidable *>(&monster) << "\n";

When I run that I get:

0
0xbfabb10c

So the grass could be cast, and the monster could not. This reduced case produces a compiler warning as well:

warning: dynamic_cast of ‘Grass grass’ to ‘class Collidable*’ can never succeed [enabled by default]

But this is not really the intent of the C++ methodology. It's better to think along the lines suggested by @bstar55 and having a virtual isCollidable() on all Objects, with some returning false. Or even to consider if there's a difference between an object isn't "collidable" and one that has a collision test that always fails. It depends on the design of your system.

Instead of trying to navigate the class hierarchy at run-time, a better focus is to think about using inheritance or "traits" when doing compile-time work. That's the real beauty of it. But it's a deep topic. I'll just point you to a couple bits like std::is_base_of and a list of other type traits.

  • Thanks for the note, I will keep that in mind next time, I was just in a bit of a rush today and couldn't really think everything through like I normally try to do. This is really helpful and thank you for directing me towards more proper habits. There is still a lot about OOP that I don't seem to know still. And no, I didn't know about the virtual destructor at all. Thank you. – Uulamock Jun 06 '14 at 23:40
  • @Uulamock No problem. These blog entries of mine might be helpful, at least I would have found them so: [Modern C++ or Modern Art](http://blog.hostilefork.com/modern-cpp-or-modern-art/), and possibly this one: [IOstreams re-examined](http://blog.hostilefork.com/iostreams-reexamined/) – HostileFork says dont trust SE Jun 07 '14 at 00:03
  • I will certainly read over these when I get the chance, thanks for helping me. This kind of information truly helps me out a ton. – Uulamock Jun 07 '14 at 00:17
1

You could dynamic_cast to determine whether object is convertible to Collidable like the example below:

int main()
{
  std::vector<Object*> objects{ new Monster(), new Wall(), new Grass() };

  for (auto i : objects){
    if (dynamic_cast<Collidable*>(i)) dynamic_cast<Collidable*>(i)->Collide();
  }
}

Display

Suggestions:

  1. foo(void) is deprecated in C++, it's a remnant from C.
  2. When use inheritance you have to make the destructor of base classes virtual to assure that destructors are called in correct order.
  3. Don't use C raw arrays instead use std::vector.
  4. Unlike the example above, don't use raw pointers but rather smart pointers like shared_ptr.
Community
  • 1
  • 1
101010
  • 41,839
  • 11
  • 94
  • 168