授予对封装容器的访问权限

时间:2011-07-26 07:28:41

标签: c++ stl iterator

class X {
  public:
    typedef std::list<int> Container;

    // (1)
    const Container& GetElements() const;

    // (2)
    Container::iterator ElementBegin();
    Container::iterator ElementEnd();

    // (3)
    CustomIterator GetElementIterator();

  private:
    Container m_container;
};

我正在寻找一种一致且干净的方法,将封装容器的迭代器提供给调用者。我想出了上面源代码中标记的三个想法。

  1. 提供size(),begin()和end(),这些都非常适合读取访问。但是,因为返回的Container引用是const,所以您只能使用const_iterator。返回引用非const是不好的,因为容器本身可以被修改(例如clear())。
  2. 提供对元素的非const访问,但是我们经常需要一个自己的size()方法(如GetElementCount())。可以使用iterator::distance(),但对于某些容器可能效率低下(重复调用operator++ / --来计算距离)。
  3. 使用next()等方法提供自定义迭代器。仍需要自己的size()方法。
  4. 我强烈打赌有更好的解决方案,所以如果你知道的话,我会很高兴看到它们。

6 个答案:

答案 0 :(得分:2)

(2)和(3)的混合可能就是我要做的事情:

class X {
  public :
    typedef std::list<int> ElementContainer;
    typedef ElementContainer::size_type ElementSizeType;
    typedef ElementContainer::iterator ElementIterator;
    typedef ElementContainer::const_iterator ConstElementIterator;

    ElementIterator elementBegin() { return m_container.begin(); }
    ElementIterator elementEnd() { return m_container.end(); }

    ConstElementIterator elementBegin() const { return m_container.begin(); }
    ConstElementIterator elementEnd() const { return m_container.end(); }

    ElementSizeType elementSize() const { return m_container.size(); }

  private :
    ElementContainer m_container;
};

它仍然留有空间来编写自定义迭代器(通过更改typedef),但只要容器提供的那些是正常的,就可以使用它们。

答案 1 :(得分:2)

我会改用这些名称:iteratorconst_iteratorbeginendcbegincend和{{1} as:

size()

如果你可以使用C ++ 0x,那么使用class X { public : typedef std::list<int>::iterator iterator; typedef std::list<int>::const_iterator const_iterator ; iterator begin() { return m_container.begin(); } iterator end() { return m_container.end(); } const_iterator cbegin() const { return m_container.begin(); } const_iterator cend() const { return m_container.end(); } size_t size() const { return m_container.size(); } private : std::list<int> m_container; }; m_container.cbegin()作为:

m_container.cend()

答案 2 :(得分:1)

我想不出更干净的方法;您可以考虑使用

提供访问权限的轻量级(4)解决方案
const Container& container() const { return m_container; }

我更喜欢(3),因为容器类型变得完全封装,即您的类型不一定需要包含,您可以更改容器类型而无需重新编译依赖模块。

答案 3 :(得分:1)

当然,最简单的是:

class X {
  public:
    typedef std::list<int> Container;

    Container m_container;
};

但这会使您的class X过时。

除此之外,如果您真的喜欢您的课程,请添加下一个方法:

Container::const_iterator ElementBegin() const;
Container::const_iterator ElementEnd() const;
int size() const;

答案 4 :(得分:0)

2和3确实不是明显的选择。然而,3写的几乎没用。没有STL算法将使用CustomIterator::next。对于STL兼容性,您可以写:

// mix of 2 and 3
CustomIterator begin();
CustomIterator end();

并提供CustomIterator标准operator++operator*

答案 5 :(得分:0)

如果您可以使用Boost,那么您可以找到一个库:http://www.boost.org/doc/libs/1_47_0/libs/iterator/doc/index.html 具体来看iterator_facade和iterator_adapter

这是一个做什么的例子 - 它提供了一个std :: vector holder,与STL兼容的迭代器。您可以通过添加其他方法来扩展它,例如operator [],size(),push_back()等。

模板 class VectorHolder { 上市:     typedef T value_type;

公共:     VectorHolder()         :m_values()     {     }

公共:     typedef typename std :: vector :: iterator vector_iterator;     typedef typename std :: vector :: const_iterator vector_const_iterator;

class iterator : public boost::iterator_adaptor<iterator, vector_iterator>
{
public:
    iterator()
        : iterator::iterator_adaptor_()
    {
    }

    iterator(const vector_iterator& it)
        : iterator::iterator_adaptor_(it)
    {
    }

private:
    friend class boost::iterator_core_access;
};

class const_iterator : public boost::iterator_adaptor<const_iterator, vector_const_iterator>
{
public:
    const_iterator()
        : const_iterator::iterator_adaptor_()
    {
    }

    const_iterator(const vector_const_iterator& it)
        : const_iterator::iterator_adaptor_(it)
    {
    }

    const_iterator(const iterator& it)
        : const_iterator::iterator_adaptor_(it.base())
    {
    }
private:
    friend class boost::iterator_core_access;
};


iterator begin()
{
    return iterator(m_values.begin());
}

iterator end()
{
    return iterator(m_values.end());
}

const_iterator begin() const
{
    return const_iterator(m_values.begin());
}

const_iterator end() const
{
    return const_iterator(m_values.end());
}protected:
std::vector<T> m_values;};