C ++重载重载方法

时间:2014-10-21 17:56:14

标签: c++

在C ++中是否有可能在子类中重载一个重写方法? 我问这个是因为我有很多子课,虽然它们是相同的(在我的情况下是游戏对象),但它们彼此之间的互动方式不同。
所以,我需要在超类中创建一个像void processCollision(GameObject obj)这样的函数 但是,根据GameObject的类别(如果它是建筑物,汽车......),这可能会在子类中重载。

我只是试图从使用upcasting和RTTI的替代方案中运行。

2 个答案:

答案 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 ++选项(访客模式)。