如何使用公共const迭代器和私有非const迭代器提供类似stl的容器?

时间:2010-03-13 18:26:26

标签: c++ stl iterator const overloading

我有一个包含std :: list的类,并且希望为const_iterator提供public begin()和end(),为plain iterator提供private begin()和end()。

然而,编译器看到私有版本并抱怨它是私有的而不是使用公共const版本。

我理解C ++不会在返回类型(在本例中为const_iterator和iterator)上重载,因此它选择非const版本,因为我的对象不是const。

在调用begin()之前将对象强制转换为const或者没有重载名称begin是否有办法实现此目的?

我认为这是人们之前已经解决过的一种已知模式,并且希望如何解决这个问题。

class myObject {
public:
  void doSomethingConst() const;
};

class myContainer {
public:
  typedef std::list<myObject>::const_iterator const_iterator;
private:
  typedef std::list<myObject>::iterator iterator;

public:
  const_iterator begin() const { return _data.begin(); }
  const_iterator end()   const { return _data.end();   }
  void reorder();
private:
  iterator begin() { return _data.begin(); }
  iterator end()   { return _data.end();   }
private:
  std::list<myObject> _data;
};

void myFunction(myContainer &container) {
  myContainer::const_iterator itr = container.begin();
  myContainer::const_iterator endItr = container.end();
  for (; itr != endItr; ++itr) {
    const myObject &item = *itr;
    item.doSomethingConst();
  }
  container.reorder(); // Do something non-const on container itself.
}

编译器的错误是这样的:

../../src/example.h:447: error: `std::_List_iterator<myObject> myContainer::begin()' is private
caller.cpp:2393: error: within this context
../../src/example.h:450: error: `std::_List_iterator<myObject> myContainer::end()' is private
caller.cpp:2394: error: within this context

感谢。

- 威廉

4 个答案:

答案 0 :(得分:5)

从std :: list派生的坏主意(它不是为了派生而来的)。

使用std :: list。

类型的成员变量
class myContainer
{
  std::list<myObject>   m_data;
  public:

    typedef std::list<myObject>::const_iterator myContainer::const_iterator;
  private:
    typedef std::list<myObject>::iterator myContainer::iterator;

  public:

    myContainer::const_iterator begin() const
    {
      return m_data.begin();
    }

    myContainer::const_iterator end() const 
    {
      return m_data.end();
    }

  private:
    myContainer::iterator begin()
    {
      return m_data.begin();
    }

    myContainer::iterator end()
    {
      return m_data.end();
    }
};

答案 1 :(得分:4)

您需要更改私人开始结束的名称。编译器不能仅通过返回类型

进行区分

这对我有用:请注意_begin _end名称

#include <list>


class myObject {};

class myContainer : private std::list<myObject> {
public:
    typedef std::list<myObject>::const_iterator const_iterator;
private:
    typedef std::list<myObject>::iterator iterator;

public:
  myContainer::const_iterator begin() const {
    return std::list<myObject>::begin();
  }
  myContainer::const_iterator end() const {
    return std::list<myObject>::end();
  }
private:
  myContainer::iterator _begin() {
    return std::list<myObject>::begin();
  }
  myContainer::iterator _end() {
    return std::list<myObject>::end();
  }
};

void myFunction(myContainer &container) {
  myContainer::const_iterator aItr = container.begin();
  myContainer::const_iterator aEndItr = container.end();
  for (; aItr != aEndItr; ++aItr) {
    const myObject &item = *aItr;
    // Do something const on container's contents.
  }
}

int main(){
    myContainer m;
    myFunction(m);
}

答案 2 :(得分:4)

我认为您唯一的选择是重命名私有方法(如果您首先需要它们)。

另外我相信你应该重命名typedef:

class MyContainer
{
public:
     typedef std::list<Object>::const_iterator iterator;
     typedef iterator const_iterator;

     const_iterator begin() const;
     const_iterator end() const;

private:
     typedef std::list<Object>::iterator _iterator;
     _iterator _begin();
     _iterator _end();
     ...
};

容器应该键入iteratorconst_iterator。接受容器的非const实例的泛型函数可能希望使用iterator typedef - 即使它不会修改元素。 (例如BOOST_FOREACH。)

就const正确性而言,这将是正常的,因为如果泛型函数实际上试图修改对象,真正的迭代器类型(作为const_iterator)将不会让它。

作为测试,以下使用您的容器进行编译:

int main()
{
    myContainer m;
    BOOST_FOREACH(const myObject& o, m) 
    {}
}

请注意,m不是const,但我们只是尝试获取包含类型的const引用,因此应允许这样做。

答案 3 :(得分:1)

您可能希望将方法Myfunction的签名更改为:

void myFunction(const myContainer &container) 

因为const方法只能在const对象上调用。目前正在发生的是你试图调用一个非const方法,在你的情况下是私有的。