【问题标题】:Custom iterator for multiple containers in C++C++中多个容器的自定义迭代器
【发布时间】:2015-09-06 16:29:36
【问题描述】:

我有一个纯抽象类和两个派生类,用于存储相同类型的数据,比如int,但在不同的数据结构中,比如mapvector

class AbstractContainer {
  public:
    virtual MyIterator firstValue() = 0;
}

class ContainerMap : public AbstractContainer {
  private:
    map<K, int>;
  public:
    MyIterator firstValue() { // return iterator over map values (int) }
}

class ContainerVector : public AbstractContainer {
  private:
    vector<int>;
  public:
    MyIterator firstValue() { // return iterator over vector values (int) }
}

ContainerMap 中,我可以继承map&lt;K, int&gt;::iterator 来迭代地图值。

但是我如何定义一个独立于数据结构的通用迭代器MyIterator,使得给定AbstractContainer 类型的指针我可以迭代值而忽略存储数据的实际结构?除此之外,这是一个好习惯吗?

编辑

这个问题是问题的简化。在我的项目中,其中一个子类将我的对象存储在内存中(在std::map 中),而另一个子类从外部数据库中检索对象。我正在尝试创建一个通用接口来访问对象集合,该接口独立于数据源,因为操作(搜索、插入和删除)将完全相同。

【问题讨论】:

  • 看看它是如何在 std 中完成的,通用的 typedefs 定义了模板中的迭代器。当然,我假设你这样做是为了好玩。这是可怕的做法。将 std 用于任何实际代码。
  • 对不起,我不明白你为什么声称这是一种可怕的做法。我尽可能将 std 用于数据结构......我只是希望我访问对象的方式对于不同的数据结构是相同的

标签: c++ iterator containers


【解决方案1】:

您想要做的是创建一个独立的迭代器类,它继承自 C++ 标准迭代器类。然后,您需要在迭代器类中实现所有标准迭代器函数(即取消引用、++、==、!= 等)。

在您的数据结构中,您可能希望有一个函数从结构中的任何点返回后继节点/值 - 该函数将由迭代器的重载 ++ 运算符调用,以便移动到下一个节点/数据结构中的值,按照您想要的顺序。例如,对于给定索引的向量,您希望后继方法返回向量中给定索引之后的索引。

不过,据我了解,您希望迭代器是通用的,这样您就可以将同一个迭代器类用于多个数据结构。这可以通过在迭代器类中使用模板和检查来实现;但是,这可能不是一个非常安全的实现 - 不推荐。

子类化标准库数据结构并在此处执行您想要执行的操作是不好的做法吗?在现实世界中,这可能被认为是不好的做法,是的。但对于实验目的或个人项目,我相信这将是一次很好的学习体验!

【讨论】:

  • 我不想从头开始实现迭代器,因为这非常危险。而且我认为这不是我需要的,因为我仍然可以在后台使用 stl 迭代器。 ContainerMap 将使用map::iterator,而ContainerVector 将使用vector::iterator。但是由于这两个迭代器没有公共基类,我没有要在 AbstractClass 中声明的类型
【解决方案2】:

嗯,不,这不是好习惯。

存在不止一种容器类型(例如,在 STL 中)的原因是没有针对所有内容进行优化的单一容器。因此,一种容器类型可能更适合元素被插入容器一次并迭代多次的用例,而另一种容器可能更适合需要从中间重复添加和删除元素的代码。

每个 STL 容器都指定自己的迭代器的原因是迭代每个容器的工作方式不同。适合使用向量的迭代器 - 充其量 - 在列表上效率低下 - 最坏 - 将无法正常工作。

也就是说,就像在 STL 中一样,没有什么可以阻止两个不同的容器使用相同的名称作为它们的迭代器。所以Container_XContainer_y都可以有一个名为Iterator的迭代器,但Container_X::Iterator不需要像Container_Y::Iterator一样工作。

您不是第一个想要与容器无关的代码的人(尽管您有效地将其表述为“与迭代器无关”)。你不会是最后一个。除非某个伟大的头脑设法指定一种容器类型,其所有操作都对所有可能的用例都是最优的(与当前的游戏状态相反,即每种容器类型对某些用例来说都是最优的,但对另一些用例来说很差)容器不可知代码是徒劳的目标。一个可以跨所有容器工作的迭代器可能会最大限度地低效,对于许多措施,对于大多数(如果不是全部)不同容器类型的一个或多个操作。

【讨论】:

  • 但是我的自定义迭代器仍然会在后台使用vector::iteratormap::iterator,每个都针对其数据结构进行了优化......所以我不明白为什么这样做效率会降低。我认为这应该起作用的方式是,例如,对我的通用迭代器的operator++ 的调用将在正在使用的容器的专用迭代器上调用operator++
  • 仅当MyIteratorAbstractContainer 是通过所有专用容器及其迭代器的内置知识实现的。每次从 AbstractContainer 派生一个新类时,您都需要修改 MyIterator 以便它可以与新容器类型的迭代器一起工作 - 同时不会破坏它与其他迭代器的工作方式。这打破了开闭原则(即设计良好的代码无需修改即可扩展),而该原则是可维护和可重用设计或代码的基础之一。
猜你喜欢
  • 2013-02-17
  • 2020-12-08
  • 2021-09-15
  • 1970-01-01
  • 2015-11-19
  • 2010-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多