繁体   English   中英

如何遍历基类对象的向量?

[英]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();

调用了正确的版本,即,如果ACircle ,则调用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 = &square;

  shapeA->intersect(shapeA);
  shapeA->intersect(shapeB);
  shapeB->intersect(shapeA);
  shapeB->intersect(shapeB);
}

请注意,这里您仍然必须列出基类中所有可能的子类,但是在这种情况下,每个基类的intersect重载形式。 如果您未能全部添加(例如,使class Triangle : public Shape ,但没有Shape::intersect(Triangle*) ),则最终将导致无限调用循环。

还要注意,在此示例中,我进行了“三重”分配,因此我不必实施将CircleSquare相交两次的逻辑。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM