我已经用迭代器(常规和常量)实现了一个双向链表,看起来工作正常,但我无法理解几件事:
1)据我所知,实现迭代器的方法之一是继承std::iterator< ... >
在模板参数中提及所有必需的类型,然后在类中键入它们...但为什么我们需要difference_type
两个迭代器?双向迭代器不能在内部重载operator - ()
所以可以不删除差异类型吗?
2)我知道它不是复制类似事物逻辑的最佳方法(在我的情况下,常规迭代器和const_iterator是两个不同的类)但是那是我现在做的,因为我对c ++模板的基本知识。我将const_iterator
作为iterator
的朋友,并使用特殊构造函数T
从const T
(节点值类型)到const_iterator(iterator &other)
进行了隐式转换,因此在返回引用时来自operator *()
它和operator->()
的指针会自动将内部ptr->_node_value
(列表节点数据)转换为const版本。这种方法还不错吗?
template <typename T>
struct DLList_node
{
T _node_value;
DLList_node<T> *_next, *_prev;
DLList_node<T>(const T& = T(), DLList_node<T> * = NULL, DLList_node<T> * = NULL);
};
template <typename T>
class DLList;
//non-const regular iterator
template<typename T>
class DLList_iterator;
//const iterator
template<typename T>
class DLList_const_iterator;
template<typename T>
class DLList_iterator :
public std::iterator< std::bidirectional_iterator_tag, T, T*, T& >
{
public:
friend class DLList<T>;
//const iterator must have access to node pointer
friend class DLList_const_iterator<T>;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
typedef std::bidirectional_iterator_tag iterator_category;
typedef DLList_node<T>* node_ptr;
DLList_iterator()
: ptr(NULL)
{}
DLList_iterator(node_ptr _ptr): ptr(_ptr)
{}
reference operator*() const
{
assert(ptr != NULL && "list iterator not dereferencable!");
return ptr->_node_value;
}
pointer operator->() const
{
assert(ptr != NULL && "list iterator not dereferencable!");
return &(ptr->_node_value);
}
bool operator == (const DLList_iterator& other) const
{
return ptr == other.ptr;
}
bool operator != (const DLList_iterator& other) const
{
return ptr != other.ptr;
}
//pre incerement
DLList_iterator& operator++()
{
assert(ptr != NULL && "list iterator not incrementable!");
ptr = ptr->_next;
return *this;
}
//post increment
DLList_iterator operator++(int)
{
assert(ptr != NULL && "list iterator not incrementable!");
DLList_iterator tmp(*this);
ptr = ptr->_next;
return tmp;
}
DLList_iterator& operator--()
{
assert(ptr != NULL && "list iterator not decrementable!");
ptr = ptr->_prev;
return *this;
}
DLList_iterator operator--(int)
{
assert(ptr != NULL && "list iterator not decrementable!");
DLList_iterator tmp(*this);
ptr = ptr->_prev;
return tmp;
}
private:
node_ptr ptr;
};
//const iterator
template<typename T>
class DLList_const_iterator :
public std::iterator< std::bidirectional_iterator_tag, const T, const T*, const T& >
{
public:
friend class DLList<T>;
typedef const T value_type;
typedef ptrdiff_t difference_type;
typedef const T* const_pointer;
typedef const T& const_reference;
typedef std::bidirectional_iterator_tag iterator_category;
typedef DLList_node<T>* node_ptr;
DLList_const_iterator()
: cptr(NULL)
{}
DLList_const_iterator(DLList_iterator<T>& _iter): cptr(_iter.ptr)
{}
DLList_const_iterator(node_ptr _ptr): cptr(_ptr)
{}
const_reference operator*() const
{
assert(cptr != NULL && "list iterator not dereferencable!");
return cptr->_node_value;
}
const_pointer operator->() const
{
assert(cptr != NULL && "list iterator not dereferencable!");
return &(cptr->_node_value);
}
bool operator == (const DLList_const_iterator & other) const
{
return cptr == other.cptr;
}
bool operator != (const DLList_const_iterator & other) const
{
return cptr != other.cptr;
}
//pre incerement
DLList_const_iterator & operator++()
{
assert(cptr != NULL && "list iterator not incrementable!");
cptr = cptr->_next;
return *this;
}
//post increment
DLList_const_iterator operator++(int)
{
assert(cptr != NULL && "list iterator not incrementable!");
DLList_const_iterator tmp(*this);
cptr = cptr->_next;
return tmp;
}
DLList_const_iterator & operator--()
{
assert(cptr != NULL && "list iterator not decrementable!");
cptr = cptr->_prev;
return *this;
}
DLList_const_iterator operator--(int)
{
assert(cptr != NULL && "list iterator not decrementable!");
DLList_iterator tmp(*this);
cptr = cptr->_prev;
return tmp;
}
private:
node_ptr cptr;
};
template <typename T>
class DLList
{
private:
node_ptr _begin, _tail;
public:
typedef DLList_iterator<T> iterator;
typedef DLList_const_iterator<T> const_iterator;
typedef DLList_node<T>* node_ptr;
typedef DLList_node<T> node;
typedef typename DLList_iterator<T>::value_type value_type;
typedef typename DLList_iterator<T>::difference_type difference_type;
typedef typename DLList_iterator<T>::pointer pointer;
typedef typename DLList_iterator<T>::reference reference;
typedef typename DLList_const_iterator<T>::const_pointer const_pointer;
typedef typename DLList_const_iterator<T>::const_reference const_reference;
//member functions and constructors here
//...
};
答案 0 :(得分:0)
1)据我所知,实现迭代器的方法之一是继承自std :: iterator&lt; ...&gt;在模板参数中提到所有必要的类型,
是
然后在你的班级中输入它们......
没有。这就是你继承std::iterator
的原因,所以你不必费心去做。
但为什么我们需要两个迭代器的difference_type?
请注意,std::iterator
默认大多数标准类型。如果您正在做一些时髦且没有标准的事情,您只需要指定差异类型。
双向迭代器不能重载operator - (),所以可以不删除差异类型吗?
您不需要提及任何类型。 std::iterator
可以帮助您完成所有工作。
2)我知道它不是复制类似事物逻辑的最佳方法(在我的情况下,常规迭代器和const_iterator是两个不同的类)但是那是我现在做的,因为我对c ++模板的基本知识。
除了检索上的一些差异之外,看看你的课程基本相同。为什么不将所有相同的代码移动到基类中。
template<typename T>
class DLList_Base_iterator :
public std::iterator< std::bidirectional_iterator_tag, T, T*, T& >
{
// Common code
protected: // allow all concrete iterators to see pointer.
node_ptr ptr;
};
template<typename T>
class DLList_iterator : public DLList_Base_iterator<T>
{
DLList_iterator(): public DLList_Base_iterator<T>(NULL) {}
DLList_iterator(node_ptr _ptr): public DLList_Base_iterator<T>(_ptr) {}
reference operator*() const {return cptr->_node_value;}
pointer operator->() const {return &(cptr->_node_value);}
};
template<typename T>
class DLList_const_iterator : public DLList_Base_iterator<T>
{
DLList_const_iterator(): public DLList_Base_iterator<T>(NULL) {}
DLList_const_iterator(node_ptr _ptr): public DLList_Base_iterator<T>(_ptr) {}
const_reference operator*() const {return cptr->_node_value;}
const_pointer operator->() const {return &(cptr->_node_value);}
};
我使const_iterator成为迭代器的朋友,并使用特殊的构造函数const_iterator(iterator&amp; other)从T(节点值类型)到const T进行隐式转换,所以当从operator *()返回引用和指针时,它和operator- &gt;()它自动将内部ptr-> _node_value(列表节点数据)转换为const版本。这种方法还不错吗?
我只想在非const迭代器中添加一个转换运算符,允许你将它转换为const版本。
template<typename T>
class DLList_iterator : public DLList_Base_iterator<T>
{
operator DLList_const_iterator<T> {
return DLList_const_iterator<T>(cptr);
}
};