【问题标题】:Derived classes' functions not being called未调用派生类的函数
【发布时间】:2015-05-04 20:38:29
【问题描述】:

我正在处理基类实体,我希望它的派生类(玩家、敌人、子弹)调用 collideWith()

我试图让 Entity 的 collideWith() 的派生函数工作,但是,基本版本总是被调用,它恰好是空的,即使我删除了关键字 virtual

基类实体

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

及其函数,在碰撞检查期间总是被调用

void Entity::collideWith(Entity*){ 

} 

具有 collideWith 函数的派生类,没有 virtual 关键字 这些在碰撞检查期间永远不会被调用

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

检查碰撞的功能 p 和 q 指向 EntityList 中的 Entity*,其中包含其派生类 玩家、敌人和子弹

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);

                    }


                }
            }
        }
    }

}

【问题讨论】:

  • 重载是根据参数的静态类型而不是动态类型来选择的。
  • 这里重要的是类接口。您的问题是基类引用Entity,派生类引用Player 等。您要么需要基类为每个派生类型提供virtual 方法,要么以其他方式实现Double Dispatch。
  • 基类的 collideWith(Entity*) 有 virtual 关键字,所以它的派生类可以重新定义它,例如 Player::collideWIth(Bullet*)
  • 参见例如:stackoverflow.com/questions/12582040/…,从中您会看到这个问题实际上是重复的。
  • 正如@OliverCharlesworth 所说,virtual 不适用于参数,而仅适用于调用对象。

标签: c++ inheritance virtual derived-class base-class


【解决方案1】:

问题是你试图让 C++ 为你做multiple dispatch,它没有做,很简单。

对于所有意图和目的,具有相同名称但参数类型不同的方法是完全不同的方法,因此不会相互覆盖。由于您的q 变量可能是Entity * 类型,因此方法调用将静态解析为对Entity::collideWith(Entity *) 的调用,而所有其他方法都将被完全忽略。

【讨论】:

  • 疯狂的是,维基百科页面在其示例代码中几乎使用了这种完全相同的情况。
  • 是的,看来我可以解决它的唯一方法是使用 wiki 示例作为模板。我会尝试看看它是否有效。我想了解更多关于这个静态调用效果的信息
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-14
  • 1970-01-01
  • 2014-01-01
  • 2011-09-17
  • 2011-06-19
  • 2012-11-06
  • 2011-09-08
相关资源
最近更新 更多