具有多态数据的容器的常见实现是什么?

时间:2015-03-21 13:27:09

标签: c++ vector polymorphism

假设我创建了一个抽象类Entity,然后创建了它的多个子类,每个子类都有其参数和功能,但由于Entity共享一个通用接口。到目前为止,这是面向对象编程中最常见的例子。

当我创建实体值向量并告诉它为N个元素保留(确保容量而不调整大小)时,内部会发生什么。如果尺寸可以是任何值,它如何知道尺寸?公共部分是存储在向量中,还是指向子类特定部分的指针?如果是这样,那么指针最终会在堆中声明?这对缓存性能非常不利。

最后,这是否与POD和非POD类型有任何关系?

3 个答案:

答案 0 :(得分:5)

如果向量包含Entity个值,则它包含类型Entity的值,而不是任何子类。由于Entity是抽象的,因此无法实例化此类向量。

如果你想要多态,你必须存储指向存储在其他地方的对象的指针,或者如果你想让向量管理它们的生命周期,就必须存储智能指针。

答案 1 :(得分:2)

一旦抽象类发挥作用,POD就会出现在窗外。你正在通过指针处理所有事情。你不关心对象的大小,因为它不是对象的向量,它是指向对象的指针向量。

如果向量拥有'内存(听起来像你的情况),然后代码看起来像这样......

// Declaration
std::vector <Entity *> ent_vector;

// Inserting into the vector
ent_vector.push_back(new EntityImpl());

// In a destructor somewhere...
for (std::vector<Entity *>::iterator i = ent_vector.begin(); i != ent_vector.end(); ++i)
{
  delete *i;
}

答案 2 :(得分:2)

在C ++中没有明确支持这种事情。您必须(如Mike的答案中所解释的)通过指针访问多态对象以调用多态行为。这意味着您必须在容器中存储指针。如果你想像往常一样想要管理对象的生命周期,你应该使用unique_ptr s。

你可以按照

的方式创建自己的小型多态容器
template<typename AbstractType>
class poly_vector
: std::vector<std::unique_ptr<AbstractType>>
{
  typedef std::vector<std::unique_ptr<AbstractType>> base;
public:
  using base::begin;                               // public access
  using base::end;                                 //   to some vector
  using base::size;                                //   functionality

  poly_vector() = default;                         // default ctor
  poly_vector(poly_vector&&) = default;            // move, but
  poly_vector(poly_vector const&) = delete;        // no copy
  // add another object at the end
  template<typename DerivedType, typename...Args>
  typename std::enable_if<std::is_base_of<AbstractType,DerivedType>::value>::type
  emplace_back(Args&&..args)
  {
    base::emplace_back(new DerivedType(std::forward<Args>(args)...);
  }
};

然而,begin()指向的对象又是指针(实际上是unique_ptr),因此访问多态对象的语义有点不寻常。 此外,emplace_back的语义不常见:您必须明确提供DerivedType作为模板参数,如myvec.emplace_back<Dervied>(arg1,arg2);

当然,您可以详细说明上述想法,包括避免双重反射的迭代器类型,以及完全分配器支持等...