继承和列表
Inheritance and lists
我需要管理蚂蚁和蚁群进行一个小游戏(实际上是为了实验)。
我有一个Element类,它定义了游戏中的所有实体(蚂蚁、殖民地、食物和其他东西…)
所有其他类都派生自此类。
我的问题:
我有一个类来管理所有实体。玩家可以选择他想要的东西。选择的实体被存储:Element* selection;
如果选择的实体是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);
};
我更倾向于避免一般的设计,因为它给我的印象充其量是一种强迫配合。
基类应该定义多个派生类之间的公共行为,并为该公共行为提供公共接口。然而,在这种情况下,在我看来,你的派生类实际上没有常见的行为,所以你在它们之间几乎没有或根本没有有用的公共接口。
在这种情况下,通过强迫它们都从一个(基本上没有意义的)"实体"类派生,你可能会损失比收获多得多。事实上,我建议,几乎任何时候,当你发现自己在思考一个像"对象"或"实体"这样笼统的类名,而这个类名并不能表明一系列有意义的行为时,你很有可能试图把不真正属于一起的东西推到一起。
话虽如此,如果你真的坚持这样做,我会坚持一条基本准则,那就是与其问,不如说。因此,我会在基类中定义一个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
至少在一个典型的情况下,即使我们告诉蚂蚁移动,我们也很可能最终处理失败的可能性,所以在要求它移动之前,添加询问物体是否可以移动的元素,实际上对我们没有任何好处。
根据情况,可能想要稍微更改代码,因此移动失败的不同原因会返回不同的错误代码,因此当/如果失败时,您可以找出原因。或者,您可能更喜欢编写代码,以便它要么成功移动,要么抛出。在这些的情况下(你宁愿它至少有一部分时间会失败),这可能不是最好的选择,但可能仍然值得考虑。
然而,我要重申的是,我认为更好的设计可能是将Ant
和Food
分开,这样就可以很容易地将食物作为食物,将蚂蚁作为蚂蚁来处理,而不必在运行时区分某个东西是食物还是蚂蚁来知道如何与它交互。
这闻起来真的像是在解决错误的问题。您可以使用isMovable
和强制转换等标志使其工作,但您的代码可能会变得一团糟,让您头疼。
也许你的问题实际上是
"我有一个类来管理所有实体"
如果它们没有任何关联,那么它们可能不应该向实体表达Is-A关系。如果每种类型都有不同的容器,可能会更干净。如何将用户想要的操作与"实体"联系起来将是另一回事。
您可以在基类上添加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
标志,因此代码片段简化为:
class Element
{
public:
Element() {}
virtual void move() {};
};
class Ant : public Element
{
public:
Ant() {}
void move() { /* move */ }
};
class Food : public Element
{
public:
Food() {}
};
- 使用继承的指针列表复制构造函数或重载运算符=
- C++:继承和列表函数作为类成员的问题
- C++具有继承列表的模板声明
- 继承向量/数组/列表并更改其大小
- 与lambda一起使用虚拟继承在初始化列表中捕获此问题的GCC错误
- 如何对 std::各种继承类的列表求和C++
- 使用类继承将单个喜欢的列表转换为双向链表
- 我如何避免明确构建C 初始化列表中继承的所有内容
- 对具有继承功能的结构使用初始值设定项列表
- 将initalizer列表与从空基类继承的结构一起使用
- 正确的语法,用于在C 中继承,并具有初始化列表和内存分配
- 从 C++ 中的两个类继承并插入到列表中
- 迭代继承的类 C++ 的列表
- 使初始化列表与 C++ 中的继承一起使用
- 为boost mpl列表中的每种类型继承容器
- 初始值设定项列表未检测到公共继承的成员
- 在C++中使用指针列表(继承还是性能?
- 有没有办法在继承构造函数时访问初始值设定项列表
- 虚拟继承会中断初始化列表显式构造函数调用
- 如何从类型列表继承,然后调用继承成员列表中的成员