最佳实践:将派生类的向量传递给基类向量上的方法

Posted

技术标签:

【中文标题】最佳实践:将派生类的向量传递给基类向量上的方法【英文标题】:Best Practice: Passing a Vector of a Derived Class to a Method on a Vector of a Base Class 【发布时间】:2014-02-03 16:34:27 【问题描述】:

这是一个“最佳实践”问题:我可以想出几种方法来做到这一点,但我想知道社区认为哪种方法最好。

我有一个方法如下:

void Foo(std::vector<BaseClass>& Objects) ...

我现在想在 Objects 上调用此方法,这是一个 std::vector&lt;DerivedClass&gt;

我可以考虑,例如,使用模板,或将 Sort 转换为采用 std::vector&lt;BaseClass*&gt;,然后传递 (Objects.begin(), Objects.end())

提前致谢。

【问题讨论】:

有什么原因你想使用自己的排序功能,而不是使用std::sort 是的(如果你愿意,我可以解释)。但它恰好是一个排序函数只是一个巧合 - 通常它可以是任何东西。我已更改问题中的名称以避免混淆 - 感谢您指出这一点。 在这种情况下,“最佳实践”将遵循人们期望的模式。标准库使用带有迭代器输入的模板函数,我强烈建议您也这样做(这会让您的生活更轻松)。 @mga 以防您不知道:小心您不能std::vector&lt;BaseClass&gt; 中存储DerivedClass,这将是对象切片的典型示例. 【参考方案1】:

如果您需要动态多态,您可以考虑使用 std::shared_ptr、std::unique_ptr 或包含指向(内部)多态类的指针的类。换句话说,'std::vector' 很丑。

如果您使用静态多态性(模板),Sort 也将成为模板。

【讨论】:

【参考方案2】:

最好的做法是接受一对迭代器来描述 Foo 应该操作的元素范围,可能提供方便的函数来将范围转换为迭代器:

template <typename Iter>
void Foo(Iter first, Iter last) ...
void Foo(std::vector<BaseClass>& Objects) 
  Foo(begin(Objects), end(Objects));

void Foo(std::vector<DerivedClass>& Objects) 
  Foo(begin(Objects), end(Objects));


// Or even a generic range adaptor,
template <typename Range>
void Foo(Range&& r) 
  using std::begin; using std::end;
  Foo(begin(r), end(r));

【讨论】:

我会避免使用便利功能,只为模板提供迭代器输入(以及可能的谓词)。这样它就与标准库保持一致,并且是人们所期望的。 这似乎是最好的方法。小问题:如果我在 Class.h 中有: template void Foo(Iter first, Iter last);我应该如何在 Class.cpp 中编写实现?如果我执行 template void Classname::Foo(Iter first, Iter last) ... 我会收到错误消息。我不得不承认我在这里有点超出我的深度。【参考方案3】:

你需要一个模板。

std::vector&lt;Base&gt;std::vector&lt;Derived&gt; 之间、std::vector&lt;Base*&gt;std::vector&lt;Derived*&gt; 之间绝对没有关系,也没有任何其他包装器。该语言不允许您在没有不安全类型转换的情况下替换这些东西,这只是未定义的行为。

如果你有一个接受std::vector&lt;Base%&gt; 的函数(用任何东西代替%),那么这就是你需要传递的。唯一的方法是创建一个正确类型的新向量并填充它。

或者你让它的功能更灵活,那就是把它做成一个模板。

【讨论】:

【参考方案4】:

如果您打算对容器的元素进行操作(例如对它们进行排序),我建议您遵循人们期望的约定:即标准库中使用的模式。

template<typename RandomAccessIterator>
void foo(RandomAccessIterator start, RandomAccessIterator end)  ... 

通过这种方式,您可以轻松地使用任何一个类(BaseDerived),并且查看您的代码的任何其他人都应该能够轻松地知道它在做什么。

如果您尝试排序,您还可以提供模板的Predicate 版本,该版本允许您提供不同于默认排序方法(例如,如果您想从最大到最小排序)。

【讨论】:

以上是关于最佳实践:将派生类的向量传递给基类向量上的方法的主要内容,如果未能解决你的问题,请参考以下文章

c ++:将指针传递给基类时访问派生类方法?

从基类类型的向量访问派生类方法

选择和修改嵌套向量中的条目的最佳实践

将指针从派生类转换为基类的最佳方法

将派生类引用传递给基类引用

C ++跨类访问基对象向量中的派生对象的引用