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);//就是如果参数相反,就调用上面的函数
    }
    //...都一样


};

猜你喜欢

转载自blog.csdn.net/qq_24328911/article/details/51475393