C ++ 11向量包含2个不同的子类,但不能同时存在

时间:2017-07-18 11:37:06

标签: c++ c++11 vector

假设我有一个基类Base,两个子类AB,后者本身就是一个子类C

我想通过设计强制std::vector可以保存任何类型的对象(包括C的子类),但一次只能保存一种类型 - 也就是说,我有一个A s的向量,或B s和C s的向量。

是否有可能在C ++ 11中使用它(当然,我可以在向向量中添加元素时强制执行此约束,但我想知道是否可以通过巧妙的设计来防止这种情况)?如何构造类层次结构来获取它?

提前感谢您的帮助!

R上。

2 个答案:

答案 0 :(得分:1)

std::vector<T>只能拥有一种类型的对象:T。它永远不能保存派生对象,或者在运行时更改类型。

通过使用间接,您可以单独分配对象,而是在向量中存储指向基类的指针。这允许向量指向派生对象,但它不会阻止同时混合不同类型。

您可以使用标记的联合实现您所描述的内容。 C ++ 11标准库没有标记的联合类型(std::variant将在C ++中引入17),所以你需要自己实现它(或者你当然可以使用第三方一如既往地实施)。标记的联合允许您列出可以存储的类型,并且一次激活一种类型。因此,您可以使用std::vector<A>std::vector<A>std::vector<C>的变体。

那就是说,你没有描述为什么你需要这个,而更好的设计可能是使用一些单独的向量。

答案 1 :(得分:1)

boost::variant< std::vector<A>, std::vector<boost::variant<B,C>> >描述了您的结构。

在C ++ 17中,将boost::替换为std::。两者非常相似,但不完全相同。

如果您无法使用boost,则必须基本上编写自己的variant

使用有点尴尬,但你的类型限制也是如此。使用auto-lambdas在C ++ 14中使用变得更容易(我相信提升变体访问者支持)。

在C ++ 14/17中,您可能会执行类似(伪代码)

的操作
template<class F, class T, class=std::enable_if_t<!is_variant<T>{}>>
decltype(auto) visit( F&& f, T&& t ) {
  return std::forward<F>(f)(std::forward<T>(t));
}
my_special_vec v;

visit( [&](auto&& v){
  for (auto&& e:v) {
    Base* b = visit( [&](auto&& e){
      e.do_operation();
      return std::addressof(e);
    }, decltype(e)(e));
    b->do_virtual_operation();
  }
}, v );

应该在您的向量包含的e.do_operation()AB中非虚拟地调用C,然后在实例上调用do_virtual_operation()作为Base

这是更简单的C ++ 14版本。 C ++ 11版本因功能对象和其他混乱而变得尴尬。