条款31:让函数根据一个以上的对象型别来决定如何虚化
如果函数有两个自变量,而这两个自变量都是继承类,我们如果根据排列组合的办法来实现继承类。RTTI或者只使用虚函数?似乎都不是好办法。Meyers给出的解决方案是自行仿真虚函数表格(Virtual Function Tables)
考虑如下代码:
#include <string>
#include <algorithm>
#include <iostream>
#include <map>
#include <typeinfo>
usingnamespacestd;
classGameObject
{
public:
GameObject(){}
virtual ~GameObject(){}
protected:
private:
};
classSpaceShip:publicGameObject
{
public:
SpaceShip(){};
virtual ~SpaceShip(){}
protected:
private:
inti;
};
classStation:publicGameObject
{
public:
Station(){}
virtual ~Station(){}
};
classAsteriod:publicGameObject
{
public:
Asteriod(){}
virtual ~Asteriod(){}
};
voidshipAsteriod(GameObject& spaceShip,GameObject& asteriod)
{
printf("shipAsteriod\n");
}
voidshipStation(GameObject& spaceShip,GameObject& station)
{
printf("shipStation\n");
}
voidasteriodStation(GameObject& asteriod,GameObject& station)
{
printf("asteriodStation\n");
}
voidasteriodShip(GameObject& asteriod,GameObject& spaceShip)
{
shipAsteriod(spaceShip,asteriod);
}
voidstationShip(GameObject& station,GameObject& spaceShip)
{
shipStation(station,spaceShip);
}
voidstationAsteriod(GameObject& station,GameObject& asteriod)
{
asteriodStation(asteriod,station);
}
typedefvoid (*HitFunctionPtr)(GameObject&,GameObject&);
typedefmap<pair<string,string> ,HitFunctionPtr> HitMap;
HitMap* initializeCollisionMap();
HitFunctionPtrlookup(conststring& class1,conststring& class2);
pair<string,string> makeStringPair(constchar* s1,constchar* s2);
voidprocessCollision(GameObject& obj1,GameObject& obj2)
{
HitFunctionPtrphf = lookup(typeid(obj1).name(),typeid(obj2).name());
if (phf)
{
phf(obj1,obj2);
}
else
throwexception();
}
pair<string,string> makeStringPair(constchar* s1,constchar* s2)
{
returnpair<string,string>(s1,s2);
}
HitMap* initializeCollisionMap()
{
HitMap *phm = newHitMap;
(*phm)[makeStringPair(typeid(SpaceShip).name(),typeid(Asteriod).name())] = &shipAsteriod;
(*phm)[makeStringPair(typeid(SpaceShip).name(),typeid(Station).name())] = &shipStation;
(*phm)[makeStringPair(typeid(Station).name(),typeid(Asteriod).name())] = &stationAsteriod;
(*phm)[makeStringPair(typeid(Station).name(),typeid(SpaceShip).name())] = &stationShip;
(*phm)[makeStringPair(typeid(Asteriod).name(),typeid(SpaceShip).name())] = &asteriodShip;
(*phm)[makeStringPair(typeid(Asteriod).name(),typeid(Station).name())] = &asteriodStation;
returnphm;
}
HitFunctionPtrlookup(conststring& class1,conststring& class2)
{
staticauto_ptr<HitMap> collisionMap(initializeCollisionMap());
HitMap::iteratoriter = collisionMap->find(makeStringPair(class1.c_str(),class2.c_str()));
if (iter == collisionMap->end())
return 0;
returniter->second;
}
intmain(intargc, char* argv[])
{
SpaceShipship;
Asteriodast;
Stations;
processCollision(ship,ast);
processCollision(ast,ship);
processCollision(s,ship);
processCollision(ship,s);
processCollision(ast,s);
processCollision(s,ast);
return 0;
}
这是一个用RTTI来实现的Virtual Function Table的仿真,那么在这个Function Table中,只需要加入合适的函数指针到map中去就可以了。千万注意的是,如果想支持RTTI,并须有虚函数存在才可以,否则……。我开始就犯了这个错误。