0

I am dealing with the base class Entity, and I want its derived classes (Player, Enemy, Bullet) to have collideWith() called

I have attempted to get the derived functions of Entity's collideWith() to work, however, the base version is always called, which happens to be empty, even when I removed the keyword virtual

Base class Entity

virtual void collideWith(Entity*);
    // Right now the derived classes of collideWIth are not being called,
    // even with the virtual removed

and its function, which is always called during collision check

void Entity::collideWith(Entity*){ 

} 

Derived classes with collideWith function, without virtual keyword These never get called during collision check

void Player::collideWith(Bullet*)
void Player::collideWith(Enemy*)
void Enemy::collideWith(Bullet*)
void Enemy::collideWith(Player*)
void Bullet::collideWith(Player*)
void Bullet::collideWith(Enemy*)

Function for checking collisions p and q points to Entity* from EntityList, which contains its derived classes Player, Enemy, and Bullet

void SceneGame::checkCollisions(){

    populateGrid();

    // Right now I am unable to get the collision detection to work!

    for (auto i = 0; i < gridBox.slicesX; ++i){
        for (auto j = 0; j < gridBox.slicesY; ++j){
            if (gridBox.cell[i][j].nEntities < 2) continue;

            for (auto k = 0; k < gridBox.cell[i][j].nEntities; ++k){
                for (auto l = 0; l < gridBox.cell[i][j].nEntities; ++l){

                    // Set up the pointers and compare them
                    auto p = gridBox.cell[i][j].items[k];
                    auto q = gridBox.cell[i][j].items[l];
                    if (p == q) continue; // we do not want the same pointer

                    if (p->getGlobalBounds().
                        intersects(q->getGlobalBounds() )){

                        // Do a series of collisions depending on the specific entities

                        /*
                          However, I end up always calling the BASE function of collideWith
                          instead of the derived types (Player, Enemy, Bullet, etc.)
                        */
                        p->collideWith(q);

                    }


                }
            }
        }
    }

}
JBRPG
  • 141
  • 1
  • 2
  • 10
  • 3
    Overloads are selected based on the *static* type of the argument, not the dynamic type. – Oliver Charlesworth Mar 04 '15 at 00:29
  • 2
    All that matters here is the class interface. Your problem is that the base class refers to `Entity` and the derived to `Player` etc. You either need the base class to have `virtual` methods for each derived type, or implement Double Dispatch in some other way. – Keith Mar 04 '15 at 00:30
  • the base class's collideWith(Entity*) has virtual keyword so its derived classes can redefine it, such as Player::collideWIth(Bullet*) – JBRPG Mar 04 '15 at 00:31
  • 1
    See for example: http://stackoverflow.com/questions/12582040/understanding-double-dispatch-c, from which you'll see that this question is effectively a duplicate. – Keith Mar 04 '15 at 00:31
  • 2
    As @OliverCharlesworth noted, the `virtual` does not apply to the parameter, but only to the invoking object. – Keith Mar 04 '15 at 00:33
  • This is a job for the Visitor pattern. – user207421 Mar 04 '15 at 00:44
  • If you're using C++11, write `void collideWith(Bullet*) override;` in the class definition , then you will get an error message if it is not actually overriding something (instead of silent wrong behaviour) – M.M Mar 04 '15 at 00:53

1 Answers1

2

The problem is that that you're trying to make C++ do multiple dispatch for you, which it doesn't do, quite simply.

Methods with the same name but different argument types are, for all intents and purposes, completely different methods, and as such do not override each other. Since your q variable is likely of type Entity *, the method call will resolve statically as a call to Entity::collideWith(Entity *), and all the other methods are ignored entirely.

Dolda2000
  • 25,216
  • 4
  • 51
  • 92
  • 1
    What's crazy is that the wikipedia page uses pretty much this exact case in its example code. – Austin Mullins Mar 04 '15 at 00:43
  • 1
    Yes, and it seems that the only way I can resolve it is by using the wiki example as a template. I will try to see if it works or not. and I want to know more about this static calling effect – JBRPG Mar 04 '15 at 00:55