[英]How can I iterate over a vector of base class objects?
我有一个问题,我们需要具有多种形状,例如可以放置在二维平面上的圆形和正方形。 所有形状(例如圆形和正方形)都从表象基类Shape继承; 因此,我有一个指向形状的指针向量。
但是,我需要能够在平面上进行迭代并找到发生碰撞的任何形状,以使它们相交或相接触。 如果我从矢量获得形状,则不知道它是正方形还是圆形,因为它已被切片为Shape基类。
我将如何最好地解决这个问题?
#ifndef Plane_h
#define Plane_h
#include <vector>
#include "Shape.h"
class Plane {
public:
Plane(std::vector<Shape*>);
Plane(const Plane&);
~Plane();
void add(Shape*);
std::vector<Shape*> all() const;
protected:
std::vector<Shape*> shapes;
};
#endif
您的课程尚未切分。 这将导致切片的对象:
vector<Shape> vec;
Circle circ;
vec.push_back(circ);
http://en.wikipedia.org/wiki/Object_slicing
在您的实例中,实例化的对象保持完整,并且指针指向整个对象-但几乎可以肯定的是,要计算交点,您将需要进行向下转换。 尽管要做到尽可能少,但这本身并不是犯罪。
最好的选择是在基类中提供一个方法,以返回指示对象类型的值-可能使用枚举-并使用它向下转换特定的Shape
指针或对正确的派生类型的指针/引用的引用。
诸如bool Intersects( const Shape& obj )
类的基础Shape
类中的抽象方法可以被派生类覆盖,该覆盖将参数向下转换为正确的派生类型。
或者,您可能希望提供采用两种形状的全局/静态方法,或者私下实现该方法并从实例方法Intersects()
调用
(检测相交并不是一件容易的事。:-))
您必须使用多态。 在Shape类上添加一个虚拟方法:
class Shape {
...
virtual bool intersects(Shape const* otherShape);
...
}
然后为每个不同的形状实现它。 然后,如果使用像:
Shape* A = getShapeA();
Shape* B = getShapeB();
if (A->intersects(B))
doSomething();
调用了正确的版本,即,如果A
为Circle
,则调用Circle::intersects
。 但在那里,您仍然不知道B
实际形状。 您可以尝试进行动态投射来找出答案:
Circle* circle = dynamic_cast<Circle*>(otherShape);
if (circle)
intersectsCircle(circle);
这是另一种方法,它不需要动态转换(或根本不需要任何显式转换),也不需要列出子类的丑陋枚举。 它基于双重调度 ,它基本上是通过两种虚拟方法来工作的,以便确定要处理的两个对象的类型。
#include <iostream>
using namespace std;
class Circle;
class Square;
struct Shape
{
virtual void intersect(Shape* otherShape) = 0;
virtual void intersect(Circle* otherCircle) = 0;
virtual void intersect(Square* otherSquare) = 0;
};
struct Circle : public Shape
{
virtual void intersect(Shape* otherShape)
{
otherShape->intersect(this);
}
virtual void intersect(Circle* otherCircle)
{
cout << "Intersecting Circle with Circle" << endl;
}
virtual void intersect(Square* otherSquare)
{
cout << "Intersecting Circle with Square" << endl;
}
};
struct Square : public Shape
{
virtual void intersect(Shape* otherShape)
{
otherShape->intersect(this);
}
virtual void intersect(Circle* otherCircle)
{
otherCircle->intersect(this);
}
virtual void intersect(Square* otherSquare)
{
cout << "Intersecting Square with Square" << endl;
}
};
int main()
{
Circle circle;
Square square;
circle.intersect(&square);
Shape* shapeA = &circle;
Shape* shapeB = □
shapeA->intersect(shapeA);
shapeA->intersect(shapeB);
shapeB->intersect(shapeA);
shapeB->intersect(shapeB);
}
请注意,这里您仍然必须列出基类中所有可能的子类,但是在这种情况下,每个基类的intersect
重载形式。 如果您未能全部添加(例如,使class Triangle : public Shape
,但没有Shape::intersect(Triangle*)
),则最终将导致无限调用循环。
还要注意,在此示例中,我进行了“三重”分配,因此我不必实施将Circle
与Square
相交两次的逻辑。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.