【问题标题】:vector of objects with inheritance in C++在 C++ 中具有继承的对象向量
【发布时间】:2011-02-17 11:52:20
【问题描述】:
class IFeature
{
public:
  virtual std::string string() = 0;
};

class Feature2D
{
public:
  virtual std::string string() { .... }
};

class Feature3D
{
public:
  virtual std::string string() { .... }
};

void print(std::vector<IFeature*> & v)
{
  for (size_t i=0; i<v.size(); i++)
    std::cout << v[i]->string() << std::endl;
}

void main()
{
  std::vector<Feature2D*> v2d;
  // push...
  print(v2d); // compile error 

  std::vector<Feature3D*> v3d;
  // push...
  print(v3d); // compile error 
}

关于如何获得此打印功能的任何建议? (可能使用与 std::vector 不同的另一个数据结构)

谢谢

【问题讨论】:

  • 您可以(并且应该)通过 const 引用将您的向量传递给print。此外,FeatureXD 类声明中缺少继承语句。
  • @Stefan - 请不要建议对问题中发布的代码进行编辑。很可能任何错误都是 OP 看到的问题的原因
  • 是的,当然,我在想什么 :)

标签: c++ inheritance vector


【解决方案1】:

使用模板。

template<typename T> void print(std::vector<T *> const & v) {
  for (size_t i=0; i<v.size(); i++)
    std::cout << v[i]->string() << std::endl;
}

或者,使用虚拟打印成员函数:

class IFeature
{
public:
  virtual std::string string() = 0;
  virtual void print(std::ostream & Dest) const = 0;
};

void print(std::vector<IFeature *> const & v) {
  for (size_t i=0; i<v.size(); i++) {
    v[i]->print(cout);
    cout << endl;
  }
}

可选地与操作符组合

inline std::ostream & operator<<(std::ostream & Dest, IFeature const & v) {
  v.print(Dest);
  return Dest;

void print(std::vector<IFeature *> const & v) {
  for (size_t i=0; i<v.size(); i++)
    std::cout << *(v[i]) << std::endl;
}

【讨论】:

  • 非常感谢!那个“const”是干什么用的?
  • 表示打印不会修改v。
【解决方案2】:

只需制作向量 IFeature* -向量。您可以在其中存储继承类的指针。

std::vector<IFeature*> v2d;
v2d.push_back(new Feature2D());
print(v2d);

无需使用模板。当您需要访问常见的虚函数时,可以使用指向超类的指针。这样你也可以在同一个向量中混合不同的子类:

std::vector<IFeature*> vMixed;
vMixed.push_back(new Feature2D());
vMixed.push_back(new Feature3D());
print(vMixed);

当然,如果您还需要继承类的指针,事情就会变得有点棘手。一种选择是将它们单独存储在其他地方。你也可以低调,但这通常是不推荐的。

【讨论】:

  • 但是,如果您需要通过向量访问继承的类,这将不起作用。 (你需要丑陋的沮丧。)
【解决方案3】:

为了完整起见,我将补充一点,您可以重新解释转换向量,因为所有向量共享相同的二进制代码。

print(reinterpret_cast<std::vector<IFeature*>&>(v2d));

C++ 没有模板参数的协方差,但如果你知道它在底层做了什么,你可以部分模拟它。我发现 reinterpret_cast 对于将 vector&lt;T*&gt;&amp; 转换为 vector&lt;const T*&gt;&amp; 以实现逆变也很有用。

当然,这很丑。

【讨论】:

    【解决方案4】:

    您可以将print 本身制作成模板:

    template<typename T>
    void print(T const &v)
    {
      for (size_t i=0; i<v.size(); i++)
        std::cout << v[i]->string() << std::endl;
    }
    

    更好的是,使用迭代器,然后它也可以在大多数其他标准容器上工作:

    template<typename T>
    void print(T const &v)
    {
      for (T::const_iterator i = v.begin(); i != v.end(); ++i)
        std::cout << (*i)->string() << std::endl;
    }
    

    更好(感谢 Pedro),自己传递迭代器:

    template<typename Iter>
    void print(Iter begin, Iter end) {
      for (Iter i = begin; i != end; ++i)
        std::cout << (*i)->string() << std::endl;
    }
    

    【讨论】:

    • 我会更进一步,建议您对迭代器进行操作,而不是对 T 的 const 引用进行操作。所以:template void print(InputIterator begin, InputIterator end) { ... }
    【解决方案5】:

    您在这里寻找的是接口协方差,这(据我所知)在 C++ 类上是不可能的。您还需要将 print 设为模板函数(将 IFeature* 替换为 T*)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-19
      • 2014-03-09
      • 2016-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-04
      • 1970-01-01
      相关资源
      最近更新 更多