C++ 如何迭代基类对象的向量?

C++ 如何迭代基类对象的向量?,c++,inheritance,stl,C++,Inheritance,Stl,我有一个问题,我们需要有很多形状,比如一个圆和一个正方形,可以放在一个平面上,二维平面上。所有形状(如圆形和方形)都继承自Abstract基类形状;因此,我有一个指向形状的指针向量 但是,我需要能够在平面上迭代并找到任何碰撞的形状,例如它们相交或接触。如果我从向量中得到一个形状,我不知道它是正方形还是圆形,因为它已经被切片为形状基类 我怎样才能最好地解决这个问题 #ifndef Plane_h #define Plane_h #include <vector> #include "

我有一个问题,我们需要有很多形状,比如一个圆和一个正方形,可以放在一个平面上,二维平面上。所有形状(如圆形和方形)都继承自Abstract基类形状;因此,我有一个指向形状的指针向量

但是,我需要能够在平面上迭代并找到任何碰撞的形状,例如它们相交或接触。如果我从向量中得到一个形状,我不知道它是正方形还是圆形,因为它已经被切片为形状基类

我怎样才能最好地解决这个问题

#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
#如果是平面#
#定义平面
#包括
#包括“Shape.h”
类平面{
公众:
平面(std::向量);
平面(常数平面&);
~Plane();
空添加(形状*);
std::vector all()常量;
受保护的:
向量形状;
};
#恩迪夫

您必须使用多态性。在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);
Circle*Circle=dynamic_cast(其他形状);
如果(圆圈)
相交圆(圆);

您必须使用多态性。在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);
Circle*Circle=dynamic_cast(其他形状);
如果(圆圈)
相交圆(圆);

您的类尚未被切片这将导致切片对象:

vector<Shape> vec;
Circle circ;
vec.push_back(circ);
vec;
圆圈圈;
向量推回(circ);

在您的实例中,实例化的对象保持完整,指针指向完整的对象——但几乎可以肯定的是,为了计算交点,您需要进行一些向下转换。虽然这是尽可能少做,但它本身并不是犯罪

最好的方法是在基类中提供一个方法,返回一个指示对象类型的值(可能使用枚举),并使用该值向下转换特定的
形状
指针或对正确派生类型的指针/引用的引用

派生类可以重写基本
Shape
类中的抽象方法,如
bool Intersects(const Shape&obj)
,该重写将参数向下转换为正确的派生类型

或者,您可能更愿意提供一个具有两种形状的全局/静态方法,或者私下实现该方法并从实例方法
Intersects()


(检测交叉点并不是一项简单的任务。:-)

您的类还没有被切片这将导致切片对象:

vector<Shape> vec;
Circle circ;
vec.push_back(circ);
vec;
圆圈圈;
向量推回(circ);

在您的实例中,实例化的对象保持完整,指针指向完整的对象——但几乎可以肯定的是,为了计算交点,您需要进行一些向下转换。虽然这是尽可能少做,但它本身并不是犯罪

最好的方法是在基类中提供一个方法,返回一个指示对象类型的值(可能使用枚举),并使用该值向下转换特定的
形状
指针或对正确派生类型的指针/引用的引用

派生类可以重写基本
Shape
类中的抽象方法,如
bool Intersects(const Shape&obj)
,该重写将参数向下转换为正确的派生类型

或者,您可能更愿意提供一个具有两种形状的全局/静态方法,或者私下实现该方法并从实例方法
Intersects()


(检测交叉点并不是一项简单的任务。:-)

这里有另一种方法,它不需要动态强制转换(或任何显式强制转换),也不需要列出子类的丑陋枚举。它基于,基本上通过两个虚拟方法来确定要处理的两个对象的类型

#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);
}
#包括
使用名称空间std;
班级圈;
班级广场;
结构形状
{
虚空相交(形状*其他形状)=0;
虚空相交(圆*其他圆)=0;
虚空相交(正方形*其他正方形)=0;
};
结构圆:公共形状
{
虚拟空心相交(形状*其他形状)
{
其他形状->相交(此);
}
虚拟空心相交(圆*其他圆)
{
不能相交(shapeB);
}
请注意,在这里您仍然必须列出基类中所有可能的子类,但在本例中,每个基类都以
intersect
重载的形式列出。如果您无法添加所有子类(例如,您制作了一个
classtriangle:public Shape
,但没有
Shape::intersect(Triangle*)
),您将得到无限的调用循环


还请注意,在这个示例中,我执行了“三重”分派,因此我不必实现将
正方形
相交两次的逻辑。

这里有另一种方法,它不需要动态强制转换(或任何显式强制转换),或列出子类的丑陋枚举。它基于,基本上通过两个虚拟方法来确定要处理的两个对象的类型

#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);
}
#包括
使用名称空间std;
班级圈;
班级广场;
结构形状
{
虚拟语音