首页 文章

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

提问于
浏览
7

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

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

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

如果没有在调用begin()之前将我的对象转换为const,或者没有重载名称,那么有没有办法实现这一点?

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

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 回答

  • 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引用,因此应该允许这样做 .

  • 4

    从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

    您需要更改私有开始端的名称 . 编译器不能仅通过返回类型进行区分

    这适用于我:注意_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);
    }
    
  • 5

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

    void myFunction(const myContainer &container)
    

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

相关问题