【问题标题】:Wierd interface method for point Iterator点迭代器的奇怪接口方法
【发布时间】:2016-09-15 19:17:02
【问题描述】:

我必须遍历周长矩形的特定点(在某些情况下,我需要遍历此矩形的一条线,在其他情况下,我需要遍历整个矩形)。我有一个接口 PointIterator。

struct Point
{
   double x,y
}
class PointIteratorI
{
     virtual void next() =0;
     virtual void isOver() =0;
     virtual Point& getPoint() = 0;
}

如果迭代超过一行

class LineIterator:public PointIterator
{
....
}

如果迭代矩形的周长

class PerimeterIterator:public PointIterator
{
   ....
}

在 LineIterator 的情况下,我还需要线的类型(水平或垂直,矩形有 2 条水平线和 2 条垂直线)。 但是像“getLineType”这样的接口对于 LineIterator 类型来说很奇怪。似乎此方法不适用于此类。因为在这种情况下,LineIterator 类将负责迭代和方向。这违反了单一职责原则。

我想到了不同的界面,例如:

class LineObjectI
{
 public:
    virtual LineType getLineType() = 0;
    .....
}
class LineIterator:public PointIterator, public LineObjectI
{
protected:
    virtual  LineType getLineType() = 0;
....
}

用于隐藏此界面。 我想知道是否有更好的方法来检查 LineIterator 上的线类型。

【问题讨论】:

  • 你错过了你有两个垂直和两个水平边缘。
  • 可能是 codereview.stackexchange.com ?

标签: c++ oop iterator single-responsibility-principle


【解决方案1】:

我将主张不同的解决方案。抛弃继承。

boost::anystd::any 开头。然后添加type erasure

以下是迭代器所需的 3 个操作:

const auto increment = make_any_method<void()>( [](auto&&self){++self;} );
const auto equals = make_any_method<bool(boost::any const&), true>( [](auto const&lhs, boost::any const& rhs){
  using LHS=std::decay_t<decltype(lhs)> const;
  auto prhs = boost::any_cast<LHS>(&rhs);
  if (!prhs) return false;
  return lhs == *prhs;
} );
template<class T>
const auto deref = make_any_method<T()>( [](auto&&self)->T {return *self;} );

现在将这些操作变成一个适当的迭代器,带有一点门面:

template<class T,
  class Base=super_any<decltype(increment), decltype(equals), decltype(deref<T>)>
>
struct poly_iterator:Base

{
  using Base::Base;
  using iterator_category = std::input_iterator_tag;
  using value_type = T;
  using difference_type = std::ptrdiff_t;
  using pointer = T*;
  using reference = T;

  friend bool operator==( poly_iterator const& lhs, poly_iterator const& rhs ) {
    return (lhs->*equals)(rhs);
  }
  friend bool operator!=( poly_iterator const& lhs, poly_iterator const& rhs ) {
    return !(lhs==rhs);
  }
  T operator*() {
    return ((*this)->*deref<T>)();
  }
  poly_iterator& operator++() {
    ((*this)->*increment)();
    return *this;
  }
  poly_iterator operator++(int) {
    std::cout << "i++\n";
    auto copy = *this;
    ((*this)->*increment)();
    return copy;
  }
};

Live example.

boost 提供与类型T 类似的类型擦除迭代器系统。

一般来说,这种技术会影响性能,因为在每次增量比较和取消引用时都遵循所有这些函数指针。

对permiter的迭代不是迭代的类型,它是一个迭代范围。

在图形的一侧(线)上迭代也是如此。

有 3 种方法可以遍历边界。首先,遍历周界中的线,然后遍历点。

其次,遍历周界的点。

第三,迭代一对(side_type,point)或(side,point),其中side具有属性side_type。

这导致迭代与 range-for 循环和 C++ 算法兼容,消除了使用智能指针的要求,并允许您将迭代器视为值类型。它将类型系统移开:您拥有类型的唯一事物是您正在迭代的事物,而不是您如何行走的细节。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-28
    • 2020-10-23
    • 2013-11-17
    • 1970-01-01
    相关资源
    最近更新 更多