【more effective c++读书笔记】【第5章】技术(7)——让函数根据一个以上的对象类型来决定如何虚化(2)

四、自行仿真虚函数表格(使用非成员函数的碰撞处理函数)

//GameObject.h
#ifndef GAMEOBJECT_H
#define GAMEOBJECT_H

class GameObject{ //抽象基类
public:
	virtual ~GameObject() = 0;
};

class SpaceShip : public GameObject{ //宇宙飞船类
public:
	virtual ~SpaceShip();
};

class SpaceStation : public GameObject{ //太空站类
public:
	virtual ~SpaceStation();
};

class Asteroid : public GameObject{ //小行星类
public:
	virtual ~Asteroid();
};

class UnkonwnCollision{//异常类
public:
	UnkonwnCollision(GameObject& whatWeHit1, GameObject& whatWeHit2);
};

#endif
//GameObject.cpp
#include"GameObject.h"
#include<iostream>

GameObject::~GameObject(){}

SpaceShip::~SpaceShip(){}

SpaceStation:: ~SpaceStation(){}

Asteroid::~Asteroid(){}

UnkonwnCollision::UnkonwnCollision(GameObject& whatWeHit1, GameObject& whatWeHit2){
	std::cout << "异常类" << std::endl;
}
//collision.h
#ifndef COLLISION_H 
#define COLLISION_H

#include "GameObject.h"  
#include<string>
#include<map>
#include<iostream>

namespace{
	//主要的碰撞处理函数   
	void shipStation(GameObject& spaceShip, GameObject& spaceStation){
		std::cout << "SpaceShip<=>SpaceStation" << std::endl;
	}
	void shipAsteroid(GameObject& spaceShip, GameObject& asteroid){
		std::cout << "SpaceShip<=>Asteroid" << std::endl;
	}
	void stationAsteroid(GameObject& spaceStation, GameObject& asteroid){
		std::cout << "SpaceStation<=>Asteroid" << std::endl;
	}
	void shipShip(GameObject& spaceShip1, GameObject& spaceShip2){
		std::cout << "SpaceShip<=>SpaceShip" << std::endl;
	}
	void stationStation(GameObject& spaceStation1, GameObject& spaceStation2){
		std::cout << "SpaceStation<=>SpaceStation" << std::endl;
	}
	void asteroidAsteroid(GameObject& asteroid1, GameObject& asteroid2){
		std::cout << "Asteroid<=>Asteroid" << std::endl;
	}
	//对称版本  
	void stationShip(GameObject& spaceStation, GameObject& spaceShip){
		shipStation(spaceShip, spaceStation);
	}
	void asteroidShip(GameObject& asteroid, GameObject& spaceShip){
		shipAsteroid(spaceShip, asteroid);
	}
	void asteroidStation(GameObject& asteroid, GameObject& spaceStation){
		stationAsteroid(spaceStation, asteroid);
	}

	typedef void(*HitFunctionPtr)(GameObject&, GameObject&); //指向碰撞函数的函数指针    
	//函数表的类型:每项关联了碰撞函数两个参数的动态类型名和碰撞函数本身  
	typedef std::map<std::pair<std::string,std::string>, HitFunctionPtr> HitMap;
    std::pair<std::string, std::string> makeStringPair(const char* s1,const char* s2);
	
	HitMap* initializeCollisionMap(); ////建立函数表
	//在函数表中查找需要的碰撞函数  
	HitFunctionPtr lookup(const std::string& class1, const std::string& class2); 
} 

void processCollision(GameObject& object1, GameObject& object2){
	//根据参数的动态类型查找相应碰撞函数  
	HitFunctionPtr phf = lookup(typeid(object1).name(), typeid(object2).name());
	if (phf)
		phf(object1, object2); //调用找到的碰撞处理函数来进行碰撞处理  
	else
		throw UnkonwnCollision(object1, object2); //没有找到则抛出异常  
}

namespace{
	std::pair<std::string, std::string> makeStringPair(const char* s1, const char* s2){
		return std::pair<std::string, std::string>(s1, s2);
	}
}

namespace{
	HitMap* initializeCollisionMap(){  //创建并初始化虚函数表  
		HitMap *phm = new HitMap; //创建函数表  
		//初始化函数表  
		(*phm)[makeStringPair(typeid(SpaceShip).name(),
			typeid(SpaceStation).name())] = &shipStation;
		(*phm)[makeStringPair(typeid(SpaceShip).name(),
			typeid(Asteroid).name())] = &shipAsteroid;
		(*phm)[makeStringPair(typeid(SpaceShip).name(),
			typeid(SpaceShip).name())] = &shipAsteroid;

		(*phm)[makeStringPair(typeid(SpaceStation).name(),
			typeid(Asteroid).name())] = &shipAsteroid;
		(*phm)[makeStringPair(typeid(SpaceStation).name(),
			typeid(SpaceShip).name())] = &shipStation;
		(*phm)[makeStringPair(typeid(SpaceStation).name(),
			typeid(SpaceStation).name())] = &shipAsteroid;

		(*phm)[makeStringPair(typeid(Asteroid).name(),
			typeid(SpaceShip).name())] = &shipAsteroid;
		(*phm)[makeStringPair(typeid(Asteroid).name(),
			typeid(SpaceStation).name())] = &asteroidStation;
		(*phm)[makeStringPair(typeid(Asteroid).name(),
			typeid(Asteroid).name())] = &asteroidAsteroid;

		return phm;
	}
}
namespace{
	//根据参数类型名在函数表中查找需要的碰撞函数  
	HitFunctionPtr lookup(std::string const& class1,
		std::string const& class2){
		//用智能指针指向返回的函数表,为静态,表示只能有一个函数表  
		static std::auto_ptr<HitMap> collisionMap(initializeCollisionMap());

		HitMap::iterator mapEntry = collisionMap->find(make_pair(class1, class2));
		if (mapEntry == collisionMap->end())
			return 0; //没找到,则返回空指针  
		return (*mapEntry).second; //找到则返回关联的碰撞函数  
	}
}

#endif    
//main.cpp
#include"Collision.h"
using namespace std;

int main(){
	SpaceShip sp;
	SpaceStation ss;
	Asteroid ad;

	processCollision(sp, ss);
	processCollision(sp, ad);
	processCollision(sp, sp);
	cout << "-----------" << endl;
	processCollision(ss, sp);
	processCollision(ss, ad);
	processCollision(ss, ss);
	cout << "-----------" << endl;
	processCollision(ad, sp);
	processCollision(ad, ss);
	processCollision(ad, ad);

	system("pause");
	return 0;
}

五、自行仿真虚函数表格(使用非成员函数的碰撞处理函数)

//GameObject.h
#ifndef GAMEOBJECT_H
#define GAMEOBJECT_H

class GameObject{ //抽象基类
public:
	virtual ~GameObject() = 0;
};

class SpaceShip : public GameObject{ //宇宙飞船类
public:
	virtual ~SpaceShip();
};

class SpaceStation : public GameObject{ //太空站类
public:
	virtual ~SpaceStation();
};

class Asteroid : public GameObject{ //小行星类
public:
	virtual ~Asteroid();
};

class UnkonwnCollision{//异常类
public:
	UnkonwnCollision(GameObject& whatWeHit1, GameObject& whatWeHit2);
};

#endif
//GameObject.cpp
#include"GameObject.h"
#include<iostream>

GameObject::~GameObject(){}

SpaceShip::~SpaceShip(){}

SpaceStation:: ~SpaceStation(){}

Asteroid::~Asteroid(){}

UnkonwnCollision::UnkonwnCollision(GameObject& whatWeHit1, GameObject& whatWeHit2){
	std::cout << "异常类" << std::endl;
}
//collision.h
#ifndef COLLISION_H 
#define COLLISION_H

#include "GameObject.h"  
#include<string>
#include<map>
#include<iostream>

//主要的碰撞处理函数   
void shipStation(GameObject& spaceShip, GameObject& spaceStation){
	std::cout << "SpaceShip<=>SpaceStation" << std::endl;
}
void shipAsteroid(GameObject& spaceShip, GameObject& asteroid){
	std::cout << "SpaceShip<=>Asteroid" << std::endl;
}
void stationAsteroid(GameObject& spaceStation, GameObject& asteroid){
	std::cout << "SpaceStation<=>Asteroid" << std::endl;
}
void shipShip(GameObject& spaceShip1, GameObject& spaceShip2){
	std::cout << "SpaceShip<=>SpaceShip" << std::endl;
}
void stationStation(GameObject& spaceStation1, GameObject& spaceStation2){
	std::cout << "SpaceStation<=>SpaceStation" << std::endl;
}
void asteroidAsteroid(GameObject& asteroid1, GameObject& asteroid2){
	std::cout << "Asteroid<=>Asteroid" << std::endl;
}
//对称版本  
void stationShip(GameObject& spaceStation, GameObject& spaceShip){
	shipStation(spaceShip, spaceStation);
}
void asteroidShip(GameObject& asteroid, GameObject& spaceShip){
	shipAsteroid(spaceShip, asteroid);
}
void asteroidStation(GameObject& asteroid, GameObject& spaceStation){
	stationAsteroid(spaceStation, asteroid);
}

#endif    
//CollisionMap.h
#ifndef COLLISIONMAP_H  
#define COLLISIONMAP_H

#include "GameObject.h"  
#include <string>  
#include <memory> 
#include <map>  

class CollisionMap{ //碰撞函数映射表  
public:
	typedef void(*HitFunctionPtr)(GameObject&, GameObject&); //指向碰撞函数的函数指针   
	//函数表的类型:每项关联了碰撞函数两个参数的动态类型名和碰撞函数本身  
	typedef std::map<std::pair<std::string, std::string>, HitFunctionPtr> HitMap;
	//根据参数类型名称向映射表中加入一个碰撞函数  
	void addEntry(const std::string& type1, const std::string& type2,
		HitFunctionPtr collisionFunction, bool symmetric = true);
	//根据参数类型名称从映射表中删除一个碰撞函数  
	void removeEntry(const std::string& type1, const std::string& type2);
	//根据参数类型名称在函数映射表中查找需要的碰撞函数  
	HitFunctionPtr lookup(const std::string& type1, const std::string& type2);
	static CollisionMap& theCollisionMap();//返回唯一的一个碰撞函数映射表  
private:
	std::auto_ptr<HitMap> collisionMap; //函数映射表,用智能指针存储  
	//构造函数声明为私有,以避免创建多个碰撞函数映射表  
	CollisionMap();
	CollisionMap(const CollisionMap&);
};

CollisionMap::CollisionMap() : collisionMap(new HitMap){}
//根据参数类型名称向映射表中加入一个碰撞函数  
void CollisionMap::addEntry(const std::string& type1, const std::string& type2,
	HitFunctionPtr collisionFunction, bool symmetric){
	if (lookup(type1, type2) == 0) //映射表中没找到时插入相应条目       
		collisionMap->insert(make_pair(make_pair(type1, type2), collisionFunction));
}
//根据参数类型名称从映射表中删除一个碰撞函数  
void CollisionMap::removeEntry(const std::string& type1, const std::string& type2){
	if (lookup(type1, type2) != 0)  //若找到,则删除该条目  
		collisionMap->erase(make_pair(type1, type2));
}
//根据参数类型名称在函数映射表中查找需要的碰撞函数  
CollisionMap::HitFunctionPtr CollisionMap::lookup(const std::string& type1, const std::string& type2){
	HitMap::iterator mapEntry = collisionMap->find(make_pair(type1, type2));
	if (mapEntry == collisionMap->end())
		return 0; //没找到,则返回空指针  
	return (*mapEntry).second; //找到则返回关联的碰撞函数  
}
//返回唯一的一个碰撞函数映射表  
CollisionMap& CollisionMap::theCollisionMap(){
	static CollisionMap cm;
	return cm;
}

void processCollision(GameObject& object1, GameObject& object2){
	//根据参数的动态类型查找相应碰撞函数  
	CollisionMap::HitFunctionPtr phf = CollisionMap::theCollisionMap().lookup(typeid(object1).name(), typeid(object2).name());
	if (phf)
		phf(object1, object2); //调用找到的碰撞处理函数来进行碰撞处理  
	else
		throw UnkonwnCollision(object1, object2); //没有找到则抛出异常  
}

#endif  
//RegisterCollisionFunction.h
#ifndef REGISTERCOLLISONFUNCTION_H
#define REGISTERCOLLISONFUNCTION_H

#include"CollisionMap.h"
#include<string>

class RegisterCollisionFunction{
public:
	RegisterCollisionFunction(const std::string& type1, const std::string& type2,
		CollisionMap::HitFunctionPtr collisionFunction, bool sysmetric = true){
		CollisionMap::theCollisionMap().addEntry(type1, type2, collisionFunction, sysmetric);
	}
};

#endif
//main.cpp
#include"Collision.h"
#include"RegisterCollisionFunction.h"
using namespace std;

RegisterCollisionFunction cf1("class SpaceShip", "class SpaceShip", &shipShip);
RegisterCollisionFunction cf2("class SpaceShip", "class SpaceStation", &shipStation);
RegisterCollisionFunction cf3("class SpaceShip", "class Asteroid", &shipAsteroid);

RegisterCollisionFunction cf4("class SpaceStation", "class SpaceStation", &stationStation);
RegisterCollisionFunction cf5("class SpaceStation", "class SpaceShip", &stationShip);
RegisterCollisionFunction cf6("class SpaceStation", "class Asteroid", &stationAsteroid);

RegisterCollisionFunction cf7("class Asteroid", "class Asteroid", &asteroidAsteroid);
RegisterCollisionFunction cf8("class Asteroid", "class SpaceShip", &asteroidShip);
RegisterCollisionFunction cf9("class Asteroid", "class SpaceStation", &asteroidStation);

int main(){
	SpaceShip sp;
	SpaceStation ss;
	Asteroid ad;

	processCollision(sp, ss);
	processCollision(sp, ad);
	processCollision(sp, sp);
	cout << "-----------" << endl;
	processCollision(ss, sp);
	processCollision(ss, ad);
	processCollision(ss, ss);
	cout << "-----------" << endl;
	processCollision(ad, sp);
	processCollision(ad, ss);
	processCollision(ad, ad);

	system("pause");
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

原文地址:https://www.cnblogs.com/ruan875417/p/4921350.html