二重调度(四):模拟虚函数表实现

有一个方法来增加选择。编译器通常创建一个函数指针数组(vtbl)来实现虚函数,并在虚函数被调用时在这个数组中进行下标索引。使用vtbl,编译器避免了使用if...then...else链,并能在所有调用虚函数的地方生成同样的代码:确定正确的vtbl下标,然后调用vtbl这个位置上存储的指针所指向的函数。 没理由说你不能这么做。如果这么做了,不但使得你基于RTTI的代码更具效率(下标索引加函数指针的反引用通常比if...then...else高效, 产生的代码也少) , 同样也将RTTI的使用范围限定在一处:你初始化函数指针数组的地方。提醒一下,看下面的内容前最好做一下深呼吸( I should mention that the meek may inherit the earth, but the meek of heart may wish to take a few deep breaths before reading what follows) 。 


对GameObjcet继承体系中的函数作一些修改:

class GameObject { 
public: 
  virtual void collide(GameObject& otherObject) = 0; 
  ... 
}; 


class SpaceShip: public GameObject { 
public: 
  virtual void collide(GameObject& otherObject); 
  virtual void hitSpaceShip(GameObject& spaceShip); 
  virtual void hitSpaceStation(GameObject& spaceStation); 
  virtual void hitAsteroid(GameObject& asteroid);
  ... 


private: 
  typedef void (SpaceShip::*HitFunctionPtr)(GameObject&); 

  typedef map<string, HitFunctionPtr> HitMap; 

  static HitMap * initializeCollisionMap(); 
  static HitFunctionPtr lookup(const GameObject& whatWeHit); 


}; 


void SpaceShip::hitSpaceShip(GameObject& spaceShip) 

  SpaceShip& otherShip= dynamic_cast<SpaceShip&>(spaceShip); 
  process a SpaceShip-SpaceShip collision; 


void SpaceShip::hitSpaceStation(GameObject& spaceStation) 

  SpaceStation& station= dynamic_cast<SpaceStation&>(spaceStation); 
  process a SpaceShip-SpaceStation collision; 


void SpaceShip::hitAsteroid(GameObject& asteroid) 

  Asteroid& theAsteroid = dynamic_cast<Asteroid&>(asteroid); 
  process a SpaceShip-Asteroid collision; 
}


SpaceShip::HitMap * SpaceShip::initializeCollisionMap() 

  HitMap *phm = new HitMap; 
  (*phm)["SpaceShip"] = &hitSpaceShip; 
  (*phm)["SpaceStation"] = &hitSpaceStation; 
  (*phm)["Asteroid"] = &hitAsteroid; 
  return phm; 
}


SpaceShip::HitFunctionPtr 
SpaceShip::lookup(const GameObject& whatWeHit) 

  static auto_ptr<HitMap> collisionMap(initializeCollisionMap()); 
                                                             
  // look up the collision-processing function for the type 
  // of whatWeHit. The value returned is a pointer-like 
  // object called an "iterator"
  HitMap::iterator mapEntry= collisionMap.find(typeid(whatWeHit).name()); 


  // mapEntry == collisionMap.end() if the lookup failed; 
  // this is standard map behavior. Again, see Item 35. 
  if (mapEntry == collisionMap.end()) 

return 0; 


  // If we get here, the search succeeded. mapEntry 
  // points to a complete map entry, which is a 
  // (string, HitFunctionPtr) pair. We want only the 
  // second part of the pair, so that's what we return. 
  return (*mapEntry).second; 

  //最后一句是return (*mapEntry).second而不是习惯上的mapEntry->second以满足
  //STL的奇怪行为
}


void SpaceShip::collide(GameObject& otherObject) 
{   

    HitFunctionPtr hfp = lookup(otherObject);                // find the function to call 
    if (hfp) {                                   // if a function was found 
      (this->*hfp)(otherObject);      // call it 
    } 
   else { 
    throw CollisionWithUnknownObject(otherObject); 
   } 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值