我有一个拥有std::shared_ptr
s私人集合的类,如:
class Foo
{
private:
using Bars = std::vector<std::shared_ptr<Bar>>;
Bars items_;
}
给定Foo
的实例,我希望能够直接迭代Bar
中的items_
个对象 - 隐藏该集合实际上包含指针。我认为唯一需要从Bars::const_iterator
更改的内容是operator*
,是否可以从中导出并实现operator*
?即。
class Iterator : public Bars::const_iterator
{
public:
Iterator(Bars::const_iterator it) : Bars::const_iterator {it} {}
const string& operator*() const
{
return *Bars::const_iterator::operator*();
}
};
然后为begin
提供end
和Foo
方法:
Foo::Iterator Foo::begin() const noexcept { return Iterator {std::cbegin(items_)}; }
Foo::Iterator Foo::end() const noexcept { return Iterator {std::cend(items_)}; }
答案 0 :(得分:3)
虽然标准库中的大多数类型都不是为了派生而来的,但在这种情况下应该没问题。继承的两个危险是切片和非虚拟破坏;对于迭代器来说,这些都不会发生。没有切片因为迭代器是作为模板参数传递的,所以总是使用确切的类型,并且没有非虚拟破坏,因为正确思想中的任何人都不会在免费存储上创建迭代器的副本,并通过指向基类型的指针删除它们(假设他们可以弄清楚它是什么。)
编辑:正如DieterLücking指出的那样,你还需要为iterator_type
提供与你的类型匹配的typedef:
typedef Iterator iterator_type;
编辑:正如DieterLücking指出的那样,单凭这一个还不够。您正在提供operator*
,并且需要提供引用该运算符的返回类型的所有typedef。
答案 1 :(得分:3)
为了灵活性,你可以写一个适配器:
#include <type_traits>
template <typename Iterator>
class random_access_pointer_iterator
{
// Types
// =====
public:
typedef Iterator iterator_type;
typedef std::random_access_iterator_tag iterator_category;
using difference_type = typename iterator_type::difference_type;
using pointer = decltype(&**std::declval<iterator_type>());
using value_type = typename std::remove_pointer<pointer>::type;
typedef value_type& reference;
// Construction
// ============
public:
explicit random_access_pointer_iterator(iterator_type iterator)
: m_iterator(iterator)
{}
// Element Access
// ==============
public:
const iterator_type& base() const { return m_iterator; }
iterator_type& base() { return m_iterator; }
operator iterator_type () const { return m_iterator; }
// Iterator
// ========
public:
reference operator * () const { return **m_iterator; }
pointer operator -> () const { return &(**m_iterator); }
random_access_pointer_iterator& operator ++ () {
++m_iterator;
return *this;
}
random_access_pointer_iterator operator ++ (int) {
random_access_pointer_iterator tmp(*this);
++m_iterator;
return tmp;
}
random_access_pointer_iterator& operator += (difference_type n) {
m_iterator += n;
return *this;
}
random_access_pointer_iterator& operator -- () {
--m_iterator;
return *this;
}
random_access_pointer_iterator operator -- (int) {
random_access_pointer_iterator tmp(*this);
--m_iterator;
return tmp;
}
random_access_pointer_iterator& operator -= (difference_type n) {
m_iterator -= n;
return *this;
}
private:
iterator_type m_iterator;
};
template <typename Iterator>
inline random_access_pointer_iterator<Iterator> operator + (
random_access_pointer_iterator<Iterator> i,
typename random_access_pointer_iterator<Iterator>::difference_type n) {
return i += n;
}
template <typename Iterator>
inline random_access_pointer_iterator<Iterator> operator - (
random_access_pointer_iterator<Iterator> i,
typename random_access_pointer_iterator<Iterator>::difference_type n) {
return i -= n;
}
template <typename Iterator>
inline typename random_access_pointer_iterator<Iterator>::difference_type
operator - (
const random_access_pointer_iterator<Iterator>& a,
const random_access_pointer_iterator<Iterator>& b) {
return a.base() - b.base();
}
template <typename Iterator>
inline bool operator == (
const random_access_pointer_iterator<Iterator>& a,
const random_access_pointer_iterator<Iterator>& b) {
return a.base() == b.base();
}
template <typename Iterator>
inline bool operator != (
const random_access_pointer_iterator<Iterator>& a,
const random_access_pointer_iterator<Iterator>& b) {
return a.base() != b.base();
}
template <typename Iterator>
inline bool operator < (
const random_access_pointer_iterator<Iterator>& a,
const random_access_pointer_iterator<Iterator>& b) {
return a.base() < b.base();
}
template <typename Iterator>
inline bool operator <= (
const random_access_pointer_iterator<Iterator>& a,
const random_access_pointer_iterator<Iterator>& b) {
return a.base() <= b.base();
}
template <typename Iterator>
inline bool operator > (
const random_access_pointer_iterator<Iterator>& a,
const random_access_pointer_iterator<Iterator>& b) {
return a.base() > b.base();
}
template <typename Iterator>
inline bool operator >= (
const random_access_pointer_iterator<Iterator>& a,
const random_access_pointer_iterator<Iterator>& b) {
return a.base() >= b.base();
}
#include <cassert>
#include <memory>
#include <vector>
int main() {
using vector = std::vector<std::shared_ptr<int>>;
auto p = std::make_shared<int>(0);
vector v = { p };
using iterator = random_access_pointer_iterator<vector::iterator>;
iterator a(v.begin());
iterator b(v.end());
assert(*a == 0);
assert(a.operator -> () == &*p);
++a;
assert(a == b);
--a;
assert(a != b);
assert(a++ != b);
assert(a-- == b);
assert(a + 1 == b);
assert(a == b - 1);
assert(b - a == 1);
assert(a < b);
assert(a <= b);
assert(b > a);
assert(b >= a);
}
有了这个,你可以使用任何随机访问迭代器(vector,deque,...)并使用任何指针类型(原始指针,shared_ptr,...)
注意:在您的情况下 - 当您从向量的迭代器派生时,您也必须调整类型定义。
注意:我不喜欢'random_access_pointer_iterator',但我没有更好的想法。