【问题标题】:How to use dynamic_cast efficiently?如何有效地使用dynamic_cast?
【发布时间】:2021-04-23 16:50:27
【问题描述】:

有一个抽象类Entity,其他类如PlayerEnemy都继承自它。当游戏检测到实体之间发生碰撞时,会调用以下方法:

    void handleCollision(Entity* ent1, Entity* ent2) {
        if (dynamic_cast<Player*>(ent1) || dynamic_cast<Player*>(ent2) &&
            dynamic_cast<Enemy*>(ent1) || dynamic_cast<Enemy*>(ent2)) {
            //player <-> enemy collision
        }
        else if (dynamic_cast<Player*>(ent1) || dynamic_cast<Player*>(ent2) &&
                 dynamic_cast<Projectile*>(ent1) || dynamic_cast<Projectile*>(ent2)) {
            //player <-> projectile collision
        }
        else if () {
            //...
        }
        else if() {
            //...
        }
    }

每个实体在与另一个实体发生碰撞时都有独特的行为,这取决于实体的类型(玩家、敌人等),这就是为什么我需要检查实体之间每个可能的组合,如上所示。但我不喜欢它创建一个巨大的 else if 链,每个实体都被检查多次的事实。还有其他方法吗?

【问题讨论】:

  • 你不想在这里upcasting,那些都是低调的......
  • 阅读“多重虚拟调度”
  • 不要使用动态转换。使用虚函数。
  • 或者std::unordered_map&lt;std::pair&lt;std::type_info, std::type_info&gt;, std::function&lt;void(Entity*, Entity*)&gt;&gt;
  • 我怀疑那些if’ 声明并没有达到它们的预期目的。 a || b &amp;&amp; c || d 被编译为就像写成 a || (b &amp;&amp;c) || d 一样。我猜它应该是(a || b) &amp;&amp; (c || d)

标签: c++ dynamic-cast multiple-dispatch


【解决方案1】:

试图扩展 Ben Voigt 关于多重虚拟调度的评论,大致如下:

void handleCollision(Entity* ent1, Entity* ent2)
{
  ent1->collide_with(ent2);
}

地点:

class Entity
{
 public:
  virtual void collide_with(Entity*) = 0; // Dispatcher

  virtual void handle_collision_with(Entity*) {}
  virtual void handle_collision_with(class Player*) {}
  virtual void handle_collision_with(class Enemy*) {}
  virtual void handle_collision_with(class Projectile*) {}
};


class Player : public Entity
{
public:
  virtual void collide_with(Entity* other) override
   {
    other->handle_collision_with(this);
   }

  virtual void handle_collision_with(Entity* other) override
   {
    // Unhandled entity
   }

  virtual void handle_collision_with(Player* other) override
   {
    // Handle collision player-player
   }

  virtual void handle_collision_with(Projectile* projectile) override
   {
    // Handle collision player-projectile
   }
};

class Enemy : public Entity
{
public:
  virtual void collide_with(Entity* other) override
   {
    other->handle_collision_with(this);
   }

  virtual void handle_collision_with(Enemy* other) override
   {
    // Handle collision enemy-enemy
   }

  virtual void handle_collision_with(Player* player) override
   {
    // Handle collision enemy-player
   }

  virtual void handle_collision_with(Projectile* projectile) override
   {
    // Handle collision enemy-projectile
   }
};

class Projectile : public Entity
{...}

来源:a-polyglots-guide-to-multiple-dispatch

【讨论】:

    【解决方案2】:

    使用Entity 类中定义的虚函数来唯一标识派生类是Player 还是Enemy。这也是避免任何运行时错误的好习惯。

     enum EntityType { Entity, Player, Enemy}
    

    在Entity类中定义一个这样的虚函数,

    virtual EntityType getType (return Entity;)
    

    并相应地在两个类中覆盖该函数。

    【讨论】:

      猜你喜欢
      • 2014-12-10
      • 2023-04-03
      • 2012-05-25
      • 2011-07-09
      • 2015-07-01
      • 2012-03-16
      • 1970-01-01
      • 2011-10-09
      • 2013-02-12
      相关资源
      最近更新 更多