#include
class CollisionWithUnknownObject {
public:
CollisionWithUnknownObject()
{
std::cout << "unknown error" << std::endl;
}
//...
};
class GameObject {
public:
virtual void collide(GameObject& otherObject) = 0;
//...
};
//The class SpaceShip Declaration
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& what);
static HitFunctionPtr lookup(GameObject& what);
typedef map< string, HitFunctionPtr > HitMap;
static HitMap* initializeCollisionMap();
};
//The class SpaceStation Declaration
class SpaceStation: public GameObject {
public:
virtual void collide(GameObject& otherObject);
virtual void hitSpaceShip(GameObject& otherObject);
virtual void hitSpaceStation(GameObject& otherObject);
virtual void hitAsteroid(GameObject& otherobject);
//...
private:
typedef void (SpaceStation::*HitFunctionPtr)(GameObject& what);
static HitFunctionPtr lookup(GameObject& what);
typedef map< string, HitFunctionPtr > HitMap;
static HitMap* initializeCollisionMap();
};
//The class Asteroid Declaration
class Asteroid: public GameObject {
public:
virtual void collide(GameObject& otherObject);
virtual void hitSpaceShip(GameObject& otherObject);
virtual void hitSpaceStation(GameObject& otherObject);
virtual void hitAsteroid(GameObject& otherobject);
//...
private:
typedef void (Asteroid::*HitFunctionPtr)(GameObject& what);
static HitFunctionPtr lookup(GameObject& what);
typedef map< string, HitFunctionPtr > HitMap;
static HitMap* initializeCollisionMap();
};
//The class SpaceShip Definition
void SpaceShip::collide(GameObject& otherObject)
{
HitFunctionPtr hfp = lookup(otherObject); //查找要调用的函数
if(hfp)
{
(this->*hfp)(otherObject);
}
else
{
throw CollisionWithUnknownObject();
}
}
SpaceShip::HitFunctionPtr
SpaceShip::lookup(GameObject& what)
{
//不好,会有付出拷贝赋值的代价
//static HitMap collisionMap = initializeCollisioniMap();
//用一个Smart Pointer
static auto_ptr
collisionMap(initializeCollisionMap());
HitMap::iterator mapEntry = collisionMap->find(typeid(what).name());
// 如果查找失败,mapEntry == collisionMap.end();
if(mapEntry == collisionMap->end())
return 0;
// 如果找到了,mapEntry会指向一个完全的map入口,
// 它是一个(string, HitFunctionPtr)对。我们只想要
// 它的第二部分,所以这是我们返回的
return (*mapEntry).second;
}
SpaceShip::HitMap*
SpaceShip::initializeCollisionMap()
{
HitMap *phm = new HitMap;
//这里书中直接就是(*phm["SpaceShip"] = &hitSpaceShip;
//而我用的是Dev-C++编译器,结果我发现
// typeid(SpaceShip).name()并不仅仅是SpaceShip,而是128SpaceShip
// 所以我做了如下修改
(*phm)[typeid(SpaceShip).name()] = &SpaceShip::hitSpaceShip;
(*phm)[typeid(SpaceStation).name()] = &SpaceShip::hitSpaceStation;
(*phm)[typeid(Asteroid).name()] = &SpaceShip::hitAsteroid;
return phm;
}
void SpaceShip::hitSpaceShip(GameObject& spaceShip)
{
SpaceShip& otherShip = dynamic_cast
(spaceShip);
std::cout << "SpaceShip collide with SpaceShip" << std::endl;
}
void SpaceShip::hitSpaceStation(GameObject& spaceStation)
{
SpaceStation& station = dynamic_cast
(spaceStation);
std::cout << "SpaceShip collide with SpaceStation" << std::endl;
}
void SpaceShip::hitAsteroid(GameObject& asteroid)
{
Asteroid& theAsteroid = dynamic_cast
(asteroid);
std::cout << "SpaceShip collide with Asteroid" << std::endl;
}
//The class SpaceStation Definition
void SpaceStation::collide(GameObject& otherObject)
{
HitFunctionPtr hfp = lookup(otherObject);
if(hfp)
{
(this->*hfp)(otherObject);
}
else
{
throw CollisionWithUnknownObject();
}
}
SpaceStation::HitFunctionPtr
SpaceStation::lookup(GameObject& what)
{
static auto_ptr
collisionMap(initializeCollisionMap());
HitMap::iterator mapEntry = collisionMap->find(typeid(what).name());
if(mapEntry != collisionMap->end())
return (*mapEntry).second;
}
SpaceStation::HitMap*
SpaceStation::initializeCollisionMap()
{
HitMap * pfm = new HitMap;
(*pfm)[typeid(SpaceShip).name()] = &SpaceStation::hitSpaceShip;
(*pfm)[typeid(SpaceStation).name()] = &SpaceStation::hitSpaceStation;
(*pfm)[typeid(Asteroid).name()] = &SpaceStation::hitAsteroid;
return pfm;
}
void SpaceStation::hitSpaceShip(GameObject& otherObject)
{
SpaceShip& ship = dynamic_cast
(otherObject);
std::cout << "SpaceStation collide with SpaceShip" << std::endl;
}
void SpaceStation::hitSpaceStation(GameObject& otherObject)
{
SpaceStation& otherSpaceStation = dynamic_cast
(otherObject);
std::cout << "SpaceStation collide with SpaceStation" << std::endl;
}
void SpaceStation::hitAsteroid(GameObject& otherObject)
{
Asteroid& theAsteroid = dynamic_cast
(otherObject);
std::cout << "SpaceStation collide with Asteroid" << std::endl;
}
//The class Asteroid Definition
void Asteroid::collide(GameObject& otherObject)
{
HitFunctionPtr hfp = lookup(otherObject);
if(hfp)
{
(this->*hfp)(otherObject);
}
else
{
throw CollisionWithUnknownObject();
}
}
Asteroid::HitFunctionPtr
Asteroid::lookup(GameObject& what)
{
static auto_ptr< HitMap > collisionMap(initializeCollisionMap());
HitMap::iterator mapEntry = collisionMap->find(typeid(what).name());
if(mapEntry != collisionMap->end())
return (*mapEntry).second;
}
Asteroid::HitMap*
Asteroid::initializeCollisionMap()
{
HitMap *pfm = new HitMap;
(*pfm)[typeid(SpaceShip).name()] = &Asteroid::hitSpaceShip;
(*pfm)[typeid(SpaceStation).name()] = &Asteroid::hitSpaceStation;
(*pfm)[typeid(Asteroid).name()] = &Asteroid::hitAsteroid;
return pfm;
}
void Asteroid::hitSpaceShip(GameObject& otherObject)
{
SpaceShip & ship = dynamic_cast
(otherObject);
std::cout << "Asteroid collide with SpaceShip" << std::endl;
}
void Asteroid::hitSpaceStation(GameObject& otherObject)
{
SpaceStation & station = dynamic_cast
(otherObject);
std::cout << "Asteroid collide with SpaceStation" << std::endl;
}
void Asteroid::hitAsteroid(GameObject& otherObject)
{
Asteroid & otherAsteroid = dynamic_cast
(otherObject);
std::cout << "Asteroid collide with Asteroid" << std::endl;
}
int main()
{
GameObject *g = new SpaceShip;
GameObject *h = new SpaceStation ;
GameObject *a = new Asteroid;
g->collide(*a);
g->collide(*h);
h->collide(*g);
h->collide(*a);
a->collide(*g);
a->collide(*h);
system("pause");
}
该程序在winXP Professinal + Dev-C++上通过,vc.net上也通过。
只是Dev-C++要求代码中的
(*pfm)[typeid(SpaceShip).name()] = &Asteroid::hitSpaceShip;
而vc中只要
(*pfm)[typeid(SpaceShip).name()] = &hitSpaceShip;
就可以了
其他类似代码处理相同