我正在研究带有自定义迭代器的通用二维容器。
现在我正在尝试为我的 begin()
和 end()
类型设置一个 iterator
和一个 constant_iterator
函数。
我的自定义迭代器在我的模板 Matrix
类中(但为了清楚起见,我将它们分开放在这里)。
template <class T>
class Matrix {
#pragma mark PUBLIC TYPEDEFS
public:
typedef T value_type;
typedef std::size_t size_type;
//typedef typename T::size_type size_type;
//typedef T::size_type size_type;
#pragma mark -
#pragma mark PRIVATE TYPEDEFS
private:
typedef T* pointer_type;
typedef T** storage_type;
#pragma mark -
#pragma mark PRIVATE VARIABLES
private:
size_type width_;
size_type height_;
storage_type data_;
// private iterators
Iterator<T*, T> m_iterator_;
Iterator<const T*, const T> m_const_iterator_;
H_Iterator<T*, T> m_hiterator_;
H_Iterator<const T*, const T> m_const_hiterator_;
#pragma mark -
#pragma mark PUBLIC VARIABLES & TYPEDEFS
public:
typedef Iterator<T*, T> iterator_type;
typedef Iterator<const T*, const T> const_iterator_type;
typedef H_Iterator<T*, T> hiterator;
typedef H_Iterator<const T*, const T> const_hiterator;
#pragma mark -
#pragma mark CONSTRUCTORS & DESTRUCTORS
public:
explicit Matrix(const std::string& fileName) {
}
Matrix(const size_type& width, const size_type& height) : width_(width),
height_(height),
data_(CreateMatrix(width, height)),
m_iterator_(*data_, width, height),
m_const_iterator_(*data_, width, height),
m_hiterator_(*data_, width, height),
m_const_hiterator_(*data_, width, height),
// fill the created matrix with default values of "T"
for (Matrix<T>::iterator_type it = this->begin(); it != this->end(); ++it)
*it = T();
}
~Matrix() {
delete [] data_[0]; // because in data_[0] is array of value_type
delete [] data_;
}
#pragma mark -
#pragma mark PRIVATE METHODS
private:
storage_type CreateMatrix(const size_type width, const size_type height) {
storage_type d = new pointer_type[height]; // array with pointers pointing to rows inside the "block"
pointer_type block = new value_type[width * height]; // one block of memory to store the data
for (size_type row = 0; row < height; ++row)
d[row] = &block[row * width];
return d;
}
#pragma mark -
#pragma mark PUBLIC METHODS
public:
hiterator h_begin(size_type row) { return m_hiterator_.begin(row); }
hiterator h_end(size_type row) { return m_hiterator_.end(row); }
const_hiterator ch_begin(size_type row) { return m_const_hiterator_.begin(row); }
const_hiterator ch_end(size_type row) { return m_const_hiterator_.end(row); }
我的内部 Iterator
类 + 派生 H_Iterator
类(H_Iterator
类用于从左到右循环一行矩阵)
#pragma mark ITERATOR CLASSES
template <typename P, typename V> // "P" - PointerType; "V" - ValueType
class Iterator : public std::iterator<std::forward_iterator_tag, T> {
protected:
P itData_;
size_type w_; // width of the matrix
size_type h_; // height of the matrix
public:
Iterator(P d, size_type width, size_type height) : itData_(d), w_(width), h_(height) { }
Iterator() { }
public:
V& operator*() const {
return *itData_;
}
Iterator<P, V>& operator++() {
++itData_;
return *this;
}
Iterator<P, V>& operator= (T value) {
*itData_ = value;
return *this;
}
P operator->() {
return itData_;
}
friend bool operator==(const Iterator& lhs, const Iterator& rhs) {
return !(lhs.itData_ != rhs.itData_);
}
friend bool operator!=(const Iterator& lhs, const Iterator& rhs) {
return !(lhs.itData_ == rhs.itData_);
}
Iterator<P, V> begin() { return Iterator<P, V>(itData_, w_, h_); }
Iterator<P, V> end() { return Iterator<P, V>(itData_ + w_ * h_, w_, h_); };
};
template <typename P, typename V> // "P" - PointerType; "V" - ValueType
class H_Iterator : public Iterator<P, V> {
public:
H_Iterator(P d, size_type width, size_type height) : Iterator<P, V>(d, width, height) { }
H_Iterator() { }
public:
H_Iterator<P, V> begin(size_type row) { return H_Iterator<P, V>(this->itData_ + this->w_ * row, this->w_, this->h_); }
H_Iterator<P, V> end(size_type row) { return H_Iterator<P, V>(this->itData_ + this->w_ * row + this->w_, this->w_, this->h_); };
};
目前,如果我想使用常量迭代器遍历其中一行,我必须这样做(=我必须使用专门为 begin
- end
和 constant_hiterator
制作的 ch_begin()
和 ch_end()
函数):
Matrix<int> m (5, 5);
for (Matrix<int>::const_hiterator hit = m.ch_begin(row); hit != m.ch_end(row); ++hit) {
cout << *hit << " ";
}
我正在努力为我的 begin()
和 end()
只有一个 const_hiterator
和 hiterator
函数。所以我可以像 std::vector 的迭代器一样编写迭代器代码:
std::vector<int> vector;
for (std::vector<int>::const_iterator it = vector.begin(); it != vector.end(); ++it) { }
for (std::vector<int>::iterator it = vector.begin(); it != vector.end(); ++it) { }
我假设我应该在 hiterator
和 const_hiterator
之间进行某种类型的转换。
最佳答案
有一些强逆风在这里抛出一些事件 Spanner 。实际上,出于一个非常简单的原因,自定义容器对于可变迭代器和常量迭代器具有单独的 begin() 和 end() 迭代器是很常见的,下面的示例对此进行了最好的证明。此示例演示了 C++ 库实现的典型容器/迭代器语义,并且通常需要自定义容器/迭代器以相同的方式实现:
class CustomContainer {
public:
class const_iterator {
// ...
};
class iterator : public const_iterator {
// ...
};
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
};
标准容器/迭代器语义不对可变和常量迭代器使用单独的 begin() 和 end() 方法。相反,object.begin() 或 pointer->begin() 最终会调用 begin() 的常量或可变版本,具体取决于 object
还是 pointer
是指向类的可变或 const
实例的引用/指针。
总结:
1) 为类的可变实例调用可变迭代器 begin()/end() 方法。
2) 类的 const 实例上的 begin()/end() 只能返回常量迭代器类型。如果您的 begin()/end() 运算符在 const 类实例上调用时会返回可变迭代器,那么这就可以通过简单地实例化其可变迭代器来修改该类的 const 实例!
3) 强烈希望可变迭代器成为常量迭代器的子类。这是自动支持将可变迭代器传递给只需要 const 迭代器参数的函数或方法的最简单方法(也可以通过定义和实现重载转换运算符来实现,但使用子类要容易得多,并且通常会带来更好的性能)。
现在,拥有一个 begin()/end() 实现当然会很方便。也不像有法律要求强制一个人始终正确支持典型的迭代器语义。
但是,正确支持这些预期的迭代器语义可以更轻松地利用 C++ 库中的所有算法,并让它们正常工作,而不会出现意外。
当然可以将可变的和常量的 begin() 和 end() 方法声明为私有(private)工厂的包装器,该工厂产生可变的开始或结束迭代器,常量 begin()/end() 外观会降低它的性能在返回之前到常量迭代器。那将是一种可能的方法。这并不理想,因为私有(private)工厂必须是常量方法,才能从常量 begin()/end() 包装器中调用它。
关于c++ - 自定义迭代器和自定义常量迭代器之间的转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34550559/