在C ++中是否有可能在子类中重载一个重写方法?
我问这个是因为我有很多子课,虽然它们是相同的(在我的情况下是游戏对象),但它们彼此之间的互动方式不同。
所以,我需要在超类中创建一个像void processCollision(GameObject obj)
这样的函数
但是,根据GameObject
的类别(如果它是建筑物,汽车......),这可能会在子类中重载。
我只是试图从使用upcasting和RTTI的替代方案中运行。
答案 0 :(得分:2)
“我只是试图从使用upcasting和RTTI的替代方案中运行。”
虚拟多态不需要upcasting或RTTI。通常这就是虚拟成员函数的用途:
class GameObject {
public:
virtual void processCollision(GameObject& obj);
};
class SomeGameObject1 : public GameObject {
public:
// SomeGameObject1's version of processCollision()
virtual void processCollision(GameObject& obj) {
// e.g here we also call the base class implementation
GameObject::processCollision();
// ... and add some additional operations
}
};
class SomeGameObject2 : public GameObject {
public:
// SomeGameObject2's version of processCollision()
virtual void processCollision(GameObject& obj) {
// Here we leave the base class implementation aside and do something
// completely different ...
}
};
更多补充和思考
当你提到向上转换时,我怀疑你想要以不同方式处理冲突,具体取决于传递的实际GameObject
类型。这确实需要上传(以及RTTI),如下所示
class Building : public GameObject {
public:
virtual void processCollision(GameObject& obj) {
Car* car = dynamic_cast<Car*>(&obj);
Airplane* airplane = dynamic_cast<Airplane*>(&obj);
if(car) {
car->crash();
}
else if(airplane) {
airplane->crash();
collapse();
}
void collapse();
};
基于以上所述,这让我沉思一些设计/建筑原则:
processCollision()
实施策略放在GameObject
类本身可能不是最佳选择。这些不应该彼此了解(否则将新的GameObject
类型引入模型将会很繁琐)GameManager
类来跟踪移动/碰撞GameObject
实例,并根据实际类型选择实现GameObjectCollisionStrategy
的{{1}}类void processCollision(GameObject& a,GameObject& b);
和a
。 b
实施和相应的策略,您应该将所有业务知识集中到GameObject
,并委托给它。 后者看起来像这样
CollisionStrategyFactory
class GameObjectCollisionStrategy {
public:
virtual processCollision(GameObject& a,GameObject& b) const = 0;
};
class CollideBuildingWithAirplane : public GameObjectCollisionStrategy {
public:
virtual void processCollision(GameObject& a,GameObject& b) const {
Building* building = dynamic_cast<Building*>(a);
Airplane* airplane = dynamic_cast<Airplane*>(b);
if(building && airplane) {
airplane->crash();
building->collapse();
}
}
};
class CollideBuildingWithCar : public GameObjectCollisionStrategy {
public:
virtual void processCollision(GameObject& a,GameObject& b) const {
Building* building = dynamic_cast<Building*>(a);
Car* car = dynamic_cast<Car*>(b);
if(building && car) {
car->crash();
}
}
};
class CollisionStrategyFactory {
public:
static const GameObjectCollisionStrategy& chooseStrategy
(GameObject* a, GameObject* b) {
if(dynamic_cast<Building*>(a)) {
if(dynamic_cast<Airplane*>(b)) {
return buildingAirplaneCollision;
}
else if(dynamic_cast<Car*>(b)) {
return buildingCarCollision;
}
}
return defaultCollisionStrategy;
}
private:
class DefaultCollisionStrategy : public GameObjectCollisionStrategy {
public:
virtual void processCollision(GameObject& a,GameObject& b) const {
// Do nothing.
}
};
// Known strategies
static CollideBuildingWithAirplane buildingAirplaneCollision;
static CollideBuildingWithCar buildingCarCollision;
static DefaultCollisionStrategy defaultCollisionStrategy;
};
或者,您可能希望选择静态多态,它也可以在没有RTTI的情况下工作,但需要在编译时已知的所有类型。基本模式是所谓的CRTP。
应该如下所示
class GameManager {
public:
void processFrame(std::vector<GameObject*> gameObjects) {
for(std::vector<GameObject*>::iterator it1 = gameObjects.begin();
it1 != gameObjects.end();
++it1) {
for(std::vector<GameObject*>::iterator it2 = gameObjects.begin();
it2 != gameObjects.end();
++it2) {
if(*it1 == *it2) continue;
if(*it1->collides(*it2)) {
const GameObjectCollisionStrategy& strategy =
CollisionStrategyFactory::chooseStrategy(*it1,*it2);
strategy->processCollision(*(*it1),*(*it2));
}
}
}
}
};
但这会不必要地使设计复杂化,我怀疑它会为您的用例提供任何好处。
答案 1 :(得分:2)
您尝试实施的内容通常称为&#34; multiple dispatch&#34;不幸的是,C ++并不直接支持它(因为在C ++视图中,方法与类有关,并且没有多方法)。
任何C ++解决方案都需要一些编码才能实现。
实现它的一种简单对称方式是为支持的案例创建一个映射:
typedef void (*Handler)(Obj *a, Obj *b);
typedef std::map<std::pair<OType, OType>, Handler> HandlerMap;
HandlerMap collision_handlers;
然后碰撞处理是:
HandlerMap::iterator i =
collision_handlers.find(std::make_pair(a->type, b->type));
if (i != collision_handlers.end()) i->second(a, b);
并且代码进入免费功能。
如果速度是关键因素,并且对象类型可以用小整数(例如0 ... 255)编码,则调度可能变为例如:
collision_handlers[(a->type<<8)+b->type](a, b);
其中碰撞处理程序只是一个函数指针数组,速度应该等于单个虚拟调度。
答案开头的维基百科链接列出了另一个更复杂的C ++选项(访客模式)。