继承和列表

时间:2013-07-16 14:10:51

标签: c++ inheritance sfml

我需要为一个小游戏管理蚂蚁和殖民地(实际上是为了实验)。

我有一个Element类,它定义了游戏中的所有实体(蚂蚁,殖民地,食物和其他东西......)

所有其他课程都来自这一课程。

我的问题:

我有一个班级来管理所有实体。玩家可以选择他想要的东西。存储选定的实体:Element* selection;如果选择的intity是Ant,则玩家可以移动它。但是,因为选择变量是一个Element指针,所以显然不能调用Ant类中的move()方法。

我考虑测试的内容:

如果我实现一个名为isMovable()的Element方法,它返回true或false,如果选择是可移动的,我会将它转换为Ant?我不知道什么是正确的解决方案。

我的移动方法:

void Manager::movementEvent(sf::Vector2i mPosition)
{
    sf::Vector2f mousePosition = sf::Vector2f((float)mPosition.x, (float)mPosition.y);
    if(this->selection) {
        // I need to move the selected Ant
    }
}

感谢您的帮助!!

修改

这是我的实际设计:

class Element {
private:
    sf::Vector2f position;
    int width, height;
public:
    Element();
    Element(sf::Vector2f position, int width, int height);
    Element(const Element & element);
    virtual ~Element();
};

class Colony: public Element {
private:
    int capacity;
    Queen *queen;

public:
    Colony();
    Colony(sf::Vector2f position, int width, int height, int capacity, Queen &queen);
    Colony(Colony const & colony);
    virtual ~Colony();

    Colony& operator=(Colony const& colony);
};

class Ant: public Element
{
private:
    sf::Vector2f destination;
    int number, age, speed;

public:
    Ant();
    Ant(sf::Vector2f position, int number, int age, int width, int height, int speed);
    Ant(const Ant & ant);
    virtual ~Ant();

    Ant& operator=(Ant const& ant);
};

class Manager {
private:
    std::vector<Element*> ants;
    std::vector<Element*> colonies;
    Element* selection;
    std::vector<Ant*> movement;
public:
    Manager();
    virtual ~Manager();

    std::vector<Element*> getAnts();
    std::vector<Element*> getColonies();

    void addAnt(Ant* ant);
    void addColony(Colony* colony);

    void removeAnt(Ant* ant);
    void removeColony(Colony* colony);

    void draw(sf::RenderWindow * window);
    void drawElement(sf::RenderWindow * window, std::vector<Element*> vector);

    void selectionEvent(sf::Vector2i mousePosition);
    bool checkSelection(sf::Vector2f mousePosition, std::vector<Element*> vector);

    void movementEvent(sf::Vector2i mousePosition);
};

3 个答案:

答案 0 :(得分:3)

我宁愿避免一般的设计,因为它最让我觉得是强迫性的。

基类应该定义许多派生类之间通用的行为,并为该常见行为提供通用接口。但是,在这种情况下,我觉得你的派生类实际上没有几乎没有共同的行为,所以你在它们之间的有用的公共接口方面几乎没有任何东西。

在这种情况下,你可能会因为强迫他们从一个(基本无意义的)“实体”类派生出来而失去更多的东西。事实上,我建议你几乎在任何时候你发现自己都在考虑一个类名称一般的“对象”或“实体”而不是暗示一组有意义的行为,那么你很有可能试图把不真正属于一起的东西推到一起。

所有这一切,如果你确实坚持要做到这一点,我会坚持一个基本的格言,最好说而不是问。因此,我在基类中定义了try_to_move(或者可能只是将它命名为move),但提供了一个失败的默认定义。然后覆盖Ant类中的实际移动。

class Entity { 
// ...
    virtual bool move_to(Location new_location) { 
        return false;
    }
};

class Ant : public Entity { 
// ...
    virtual bool move_to(Location new_location) { 
        my_location = new_location; 
        return true;
    }
};

通过这种方式,您可以告诉从Entity派生的任何 - 但如果您告诉Food对象移动,它就会失败。这大大简化了调用代码。而不是像这样的模式:

if (object->can_move()) {
    if (object->move_to(new_location))
        // succeeded
    else
        // failed
}

我们得到的代码如下:

if (object->move_to(new_location))
     // succeeded
else
     // failed

至少在一个典型的情况下,即使我们告诉蚂蚁移动,我们也可能最终处理失败的可能性,因此在要求对象之前添加询问对象是否可以移动的元素无论如何,这样做真的让我们无所适从。

根据具体情况,可能想要稍微更改代码,因此无法移动的不同原因会返回不同的错误代码,因此当/如果失败,您可以理清原因。或者,您可能更喜欢编写代码,以便它在移动时成功,或者抛出。在这些情况下(你宁愿在至少部分时间内失败)这可能不是最好的选择,但可能仍然值得考虑。

然而,我会重申,我认为一个更好的设计可能只是让AntFood分开,所以很容易将食物作为食物,蚂蚁作为蚂蚁,并且无需在运行时进行整理,无论是Food还是Ant,都知道如何与它进行交互。

答案 1 :(得分:1)

这真的闻起来像是在解决错误的问题。您将能够使用isMovable等标记和强制转换来使其工作,但您的代码可能会变得一团糟,让您头疼。
也许你的问题实际上是

  

“我有一个班级来管理所有实体”

如果它们没有任何关联,它们可能不应该表达与实体的Is-A关系。如果每种类型都有不同的容器,它可能会更清洁。如何将用户想要的操作与“实体”联系起来将是另一回事。

答案 2 :(得分:1)

您可以在基类上添加virtual方法move(),而不是仅为Ant类实现,因此当检查Element时,class Element { public: Element(bool movable) : m_movable(movable) {} virtual void move() {}; bool isMovable() const { return m_movable; } private: bool m_movable; }; class Ant : public Element { public: Ant() : Element(true) {} void move() { /* move */ } }; class Food : public Element { public: Food() : Element(false) {} }; 是可移动的,应该动:

move()

这样,每个派生类都有一个bool m_movable方法,但它是从基类继承的(所以它留空)。

修改

Occam的剃刀告诉我们,在这种情况下,您也不需要class Element { public: Element() {} virtual void move() {}; }; class Ant : public Element { public: Ant() {} void move() { /* move */ } }; class Food : public Element { public: Food() {} }; 标志,因此该片段简化了:

{{1}}