0

例如,是否应将以下类分为两部分:

class Range {
 public:
  Range(int end);

  Range begin();
  Range end();

  // Second class would contain these methods.
  bool operator!=(const Range& range);
  int operator*();
  void operator++();
};

// Print 012
// Almost as pretty as Python :D
for (int i : Range(3)) {
  std::cout << i;
}

?

PS:标准库中有这样的类吗?

更新:

以下是替代设计的外观:

class Range;

class RangeIterator {
 public:
  bool operator!=(const RangeIterator& range_iterator);
  int operator*();
  void operator++();

 private:
  RangeIterator(const Range& range);
};

class Range {
 public:
  Range(int end);

  RangeIterator begin();
  RangeIterator end();

  friend class RangeIterator;
};
4

3 回答 3

2

就我个人而言,我会把它分开——C++ 中类型安全的要点是,当你将一个范围传递给一个应该采用迭代器的函数时,编译器会告诉你,反之亦然。如果同一个类同时扮演这两个角色,那么你就失去了这个,如果myrangemyrange.begin()具有相同的类型,这是一个现实的错误。也就是说,由于您也喜欢 Python,您可能不会认为这有什么大不了的,您已经习惯了存在__iter__返回的对象self。从 C++ POV 我会说这可能看起来有点不寻常/棘手/聪明。

不过,这并不意味着RangeIterator必须在您的界面中公开定义。您可以使用Range::iterator_type由私有嵌套类或命名空间中定义的类支持的 typedef 。Range::iterator_type无论哪种方式,有人可以检查头文件中的类定义,但除了“可以通过名称引用它,这就是你可以用它做什么”之外,您不会记录任何内容。

说到这一点,目前Range也不RangeIterator满足迭代器的要求。如果您决定要Iterator成为迭代器,那么您需要专门std::iterator_traits化,添加一些 typedef,或者(常用选项)派生自std::iterator. 因此,无论您采用哪种方式,都需要包含更多样板文件。这可能会影响你的决定。您开始编写的内容越多,按比例定义额外类的成本就越少。

这里RangeIterator变成了一个迭代器:

class RangeIterator : public std::iterator<std::input_iterator_tag, int> {
 public:
  bool operator!=(const RangeIterator& range_iterator) const;
  bool operator==(const RangeIterator& range_iterator) const;
  int operator*() const;
  RangeIterator &operator++();
  RangeIterator operator++(int);

 private:
  RangeIterator(const Range& range);
};
于 2013-02-04T08:55:08.553 回答
0

是否应该将其分为两类在很大程度上取决于使用该软件的环境。

例如,如果软件的其余部分与这种类型的代码无关,那么将它们放在一起可能是有意义的,并且可以降低复杂性。另一方面,如果您正在努力拥有某种通用实用程序,那么将它们分开可能会更好地维护可维护性(或者可以说,为了简单起见)。

我认为您应该考虑可维护性和可读性,而不是对这样的代码片段制定硬性规则。从长远来看,您的设计选择会让事情更容易维护吗?它会降低项目的复杂性吗?

这就是软件架构设计中的一件很酷的事情!

于 2013-02-04T07:38:59.857 回答
0

我会简单地坚持第二种方法,它有一些好处:

  1. 您可能希望以Range不同的方式遍历,具体取决于您要完成的任务。但是您可能不希望 Range使用针对不同遍历的操作来使界面膨胀,即使您可以预料到您将需要的操作。

  2. 将遍历机制与Range对象分离让我们可以为不同的遍历策略定义迭代器,而无需在Range接口中枚举它们。例如, FilteringRangeIterator可能只提供对那些满足特定过滤约束的元素的访问。

  3. 您可能希望为 提供多态性Range,然后可以泛化迭代器概念以支持多态迭代。

于 2013-02-04T09:04:19.743 回答