item31讓函數根據一個以上的對象類型來決定如何虛化

#include <iostream>
/*
    >如果宇宙飛船以低速與太空站碰撞,宇宙飛船會泊進太空站(程序沒有涉及)
    否則宇宙飛船和太空站受到的損害與其速度成正比

    >如果宇宙飛船與宇宙飛船碰撞,或是太空站與太空站碰撞,都會受損,受到的損害與其速度成正比

    >如果小號的小行星與宇宙飛船或太空站相撞,小行星會損毀。如果碰到的是大號小行星,
    那宇宙飛船或太空站損毀

    >如果小行星撞擊另一顆小行星,兩者都碎裂成更小的小行星,且想四面八方散去
*/
class GameObject{ ... };
class SpaceShip : public GameObject{... };
class SpaceStation : public GameObject{... };
class Asteroid : public GameObject{... };

void checkForCollision(GameObject&, GameObject&)
{
    if(theyJustCollision(lhs, rhs))
        processCollision(lhs, rhs)
        else
        ...
}//

//virtual fcn + RTTI
// if_then_else way
class GameObject{ 
    virtual void collide(GameObject& otherObject) = 0;
 };
class SpaceShip : public GameObject{... };
class SpaceStation : public GameObject{... };
class Asteroid : public GameObject{... };

class CollisionWithUnKnowObject{//except class
public:
    CollisionWithUnKnowObject(GameObject& whatWeHit);//why?
}
void SpaceShip::collide(GameObject& otherObject)
{
    const type_info& objectType = typeid(otherObject);//lookup typeid & type_info

    if(objectType == typeid(SpaceShip))
        SpaceShip& ss = static_cast<SpaceShip&>(otherObject);

    process a SpaceShip-SpaceShip collision;
    else if (objectType == typeid(SpaceStation))//--copy
        SpaceShip& ss = static_cast<SpaceStation&>(otherObject);

    process a SpaceShip-SpaceStation collision;
    else if (objectType == typeid(Asteroid))
        SpaceShip& ss = static_cast<Asteroid&>(otherObject);

    process a SpaceShip-Asteroid collision;//copy end
    else
        throw CollisionWithUnKnowObject(otherObject);
};

/*
*/

/////////////////////////////////////
 //overload只用虛函數,有圖1
class GameObject{ 
public:
    virtual void collide(GameObject& otherObject) = 0;
    virtual void collide(SpaceShip& otherObject) = 0;
    virtual void collide(SpaceStation& otherObject) = 0;
    virtual void collide(Asteroid& otherObject) = 0;
 };
class SpaceShip : public GameObject{
public:
    virtual void collide(GameObject& otherObject) ;
    virtual void collide(SpaceShip& otherObject) ;
    virtual void collide(SpaceStation& otherObject) ;
    virtual void collide(Asteroid& otherObject) ;
 };

//impoint point:
virtual void collide(GameObject& otherObject) 
{
    otherObject.collide(*this);
}
//
class SpaceStation : public GameObject{... };
class Asteroid : public GameObject{... };

//////////////////////////////////////
// virtual FCN Tables way
class GameObject{ 
public:
    virtual void collide(GameObject& otherObject) ;
    virtual void hitSpaceShip(SpaceShip& otherObject) ;
    virtual void hitSpaceStation(SpaceStation& otherObject) ;
    virtual void hitAsteroid(Asteroid& otherObject) ;
 };

class SpaceShip : public GameObject{
private://!!
    typedef void (SpaceShip::*HitFCNPtr)(GameObject&);//!!
    static HitFCNPtr lookup(const GameObject& whatWeHit);
 };
void SpaceShip::collide(GameObject& otherObject)
{
    HitFCNPtr hfp = lookup(otherObject);

    if(hfp)
    { this->*hfp}(otherObject);
    else
        throw CollisionWithUnKnowObject(otherObject);
}
class SpaceShip : public GameObject{
private:
    typedef void (SpaceShip::*HitFCNPtr)(GameObject&);
    typedef map<string, HitFCNPtr> HitMap;
 };
void SpaceShip::lookup()
{
    static HitMap collisionMap;//static in fcn !!

    //init
    collisionMap["SpaceShip"] = &hitSpaceShip;
    collisionMap["SpaceStation"] = &hitSpaceStation;
    collisionMap["Asteroid"] = &hitAsteroid;//error

    HitMap::iterator mapEntry = 
        collisionMap.find(typeid(wharWeWait).name())//typeid::name
        if(mapEntry == collision.end())
            return 0;
        return (*mapEntry).second;
}

//make init be smart ptr 
//雖然只是爲了調用時初始化,但好像簡便了許多
class SpaceShip : public GameObject{
private://!!
    static HitMap * initCollisionMap();
 };

SpaceShip::HitFCNPtr
SpaceShip::lookup(const GameObject& otherObject)
{
    static auto_ptr<HitMap>
        collisionMap(initCollisionMap() );
}
SpaceShip::HitMap * SpaceShip::initCollisionMap()
{
    HitMap* phm = new HitMap;
    (*phm)["SpaceShip"] = &hitSpaceShip;
    (*phm)["SpaceStation"] = &hitSpaceStation;
    (*phm)["Asteroid"] = &hitAsteroid;

    return phm;
}
//但上面的會出錯,因爲map的元素:函數指針的類型不一樣
//因參數類型不一樣。也不符合聲明
SpaceShip::HitMap * SpaceShip::initCollisionMap()
{
    HitMap * phm = new HitMap;
    (*phm)["SpaceShip"] = 
        reinterpret_cast<HitFCNPtr>(&hitSpaceShip);
    (*phm)["SpaceStation"] = 
        reinterpret_cast<HitFCNPtr>(&hitSpaceStation);
    (*phm)["Asteroid"] = 
        reinterpret_cast<HitFCNPtr>(&hitAsteroid);

    return phm;
}
//圖2
//所謂reinterpret_cast 能不用就不用,解決辦法是

class SpaceShip : public GameObject{ 
public:
    virtual void collide(GameObject& otherObject) ;
    virtual void hitSpaceShip(GameObject& otherObject) ;
    virtual void hitSpaceStation(GameObject& otherObject) ;
    virtual void hitAsteroid(GameObject& otherObject) ;
    /*參數類型一致了*/
 };

/*夾帶真是性,我覺得我這一步有些多餘,但爲了消除使用者困惑*/
void SpaceShip::hitSpaceShip(GameObject& spaceShip) 
{
    SpaceShip& otherShip
        = dynamic_cast<SpaceShip&>(spaceShip);
    process a SpaceShip-SpaceShip collision;
}
void SpaceShip::hitSpaceStation(GameObject& spaceStation){...}
void SpaceShip::hitAsteroid(GameObject& asteroid){...}

//use non_member fcn to process a collision fcn

#include "SpaceShip.h"
#include "spaceStation"
#include "Asteroid"

namespace{
    void shipAsteroid(GameObject& spaceShip,GameObject &asteroid);
    void shipStation(GameObject& spaceShip,GameObject &spaceStation);
    void StationAsteroid(GameObject& spaceStation,GameObject &asteroid);

    void Asteroidship(GameObject& asteroid,GameObject &spaceShip)
    {
        shipAsteroid(asteroid,spaceShip);//就是如果參數相反,就調用上面的函數
    }
    //...都一樣


};
發佈了60 篇原創文章 · 獲贊 4 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章