'无效协变返回类型#39;嵌套迭代器和接口中的错误

时间:2014-08-30 17:15:36

标签: c++ iterator nested

我正在尝试创建一个名为Matrix的界面。两个类将实现此接口。 其中之一称为RegMatrix(常规矩阵)。 现在,我正在尝试为RegMatrix和OthMatrix类构建迭代器,并让用户能够迭代'Matrix'对象。 问题是我得到一个错误“对于方法begin()和end()的'虚拟RegMatrix :: iterator RegMatrix :: begin()'”的无效协变返回类型,可能是因为其中一个返回一个RegMatrix: :iterator,基类返回Matrix :: iterator。我不明白这是什么意思。有人知道如何解决这个问题吗? 感谢。

编辑: 我从你目前的答案中了解到我的设计无效。那么,有人能为我的问题提出更好的设计/解决方案吗?迭代'矩阵',可以是'RegMatrix'(用Map保存数据实现)或'OthMatrix'实例(用Vector实现)。那两个有不同的迭代器,我想要一个Wrapper迭代器来包装这两个,所以这种实例在迭代时对用户是透明的。感谢。

Class Matrix(界面):

class Matrix
{
public:
    class iterator
    {
    public:
        virtual iterator& operator=(const iterator &other);
        virtual ~iterator(){}
        double operator*() const;
        bool operator==(const iterator &other) const;
        bool operator!=(const iterator &other) const;
        iterator &operator++();
        iterator &operator++(int);
    };

    virtual iterator begin() = 0;  //*** ERROR : overriding 'virtual Matrix::iterator Matrix::begin()' ***
    virtual iterator end() = 0;   //*** ERROR : overriding 'virtual Matrix::iterator Matrix::end()' ***

};

类规则矩阵:

class RegMatrix : public Matrix
{
public:
    RegMatrix() {//TODO };

    class iterator : public Matrix::iterator{

          friend class RegMatrix;

      public:

        iterator& operator=(const iterator &other) {
           //TODO
        }

        ~iterator() {}

        double operator*() const {
          //TODO
        }


        bool operator==(const iterator &other) const {
            //TODO
        }

        bool operator!=(const iterator &other) const {
          //TODO
        }

        iterator &operator++() {
            //TODO
        }

        iterator &operator++(int)
        {
            //TODO
        }

      iterator(Vector2D::iterator place)
      {
          rowIter = place;
      }
      private:
            Vector2D::iterator rowIter;
            Vector::iterator colIter;

      };

      iterator begin() {  //*** ERROR : invalid covariant return type for 'virtual RegMatrix::iterator RegMatrix::begin()' *** //
        return iterator(matrix.begin());
      }

      iterator end() {  //*** ERROR : invalid covariant return type for 'virtual RegMatrix::iterator RegMatrix::end()' *** //
            return iterator(matrix.end());
      }

private:
    Vector2D matrix;
};

2 个答案:

答案 0 :(得分:1)

您的代码无效,因为您尝试使用Matrix::iterator Matrix::begin()覆盖RegMatrix::iterator RegMatrix::begin();返回类型不同。仅当返回类型为“协变”时才允许这样做:

  

§10.3.7

     

覆盖函数的返回类型应与...相同   被重写函数的返回类型或与变量的协变   功能的类。如果函数D :: f覆盖函数   B :: f,函数的返回类型如果满足则是协变的   以下标准:

     
      
  • 都是指向类的指针,都是对类的左值引用,或者两者都是对类的右值引用
  •   
  • B :: f的返回类型中的类与D :: f的返回类型中的类是同一个类,或者是一个明确且可访问的直接类   或者返回类型为D :: f
  • 的类的间接基类   
  • 指针或引用都具有相同的cv限定,并且返回类型D :: f中的类类型具有相同的cv限定条件   或者比返回类型中的类类型更少的cv资格   B :: F。
  •   

因为返回类型既不是指针也不是引用,它们不能是协变的。

您可以使用Pimpl成语来修复您的设计;它允许有一个单一的迭代器类型,它能够通过注入一个具体的实现来迭代不同的容器类型。

这是一个显示基本概念的精简示例:

#include <memory>

class Matrix
{
public:
    class iterator
    {
    public:
        // this is the interface for the implementation the iterator is using
        struct impl
        {
            virtual ~impl() {}
            virtual double dereference() const = 0;
            // [...]
        };

        // the constructor takes a implementation
        iterator(std::unique_ptr<impl> impl)
            : m_impl{std::move(impl)}
        {
        }

        double operator*() const
        {
            // all calls are referred to the concrete implementation
            return m_impl->dereference();
        }

        // [...]

    private:
        std::unique_ptr<impl> m_impl;
    };

    virtual iterator begin() = 0;
    virtual iterator end() = 0;
};

class RegMatrix : public Matrix
{
    // every Matrix has its own iterator implementation
    class iterator_impl : public Matrix::iterator::impl 
    {
    public:
        iterator_impl(Vector2D::iterator itr)
            : m_itr{itr}
        {
        }

        virtual double dereference() const override
        {
            return *m_itr;
        }
        // [...]

    private:
        Vector2D::iterator m_itr;
    };

    virtual iterator begin() override
    {
        // return a iterator that holds our iterator implementation
        return iterator(std::unique_ptr<iterator_impl>{new iterator_impl{matrix.begin()}});
    }

    virtual iterator end() override
    {
        return iterator(std::unique_ptr<iterator_impl>{new iterator_impl{matrix.end()}});
    }

private:
    Vector2D matrix;
};

这应该能够解决您的问题,但它也有缺点:每个迭代器构造都会引发堆分配,并且每个迭代器操作都会导致虚拟方法调用。这可能会成为关键情况下的性能问题,尤其是因为迭代器应该是轻量级对象。

答案 1 :(得分:0)

只有在返回指针或引用(相应地返回到基类和派生类)时才允许使用协变返回类型 - 而不是在按值返回时。

考虑一下 - 调用者需要知道为存储返回值需要多少内存。但是sizeof(RegMatrix::iterator) > sizeof(Matrix::iterator)。如果只有Matrix*指针的调用者应该知道哪个begin()调用将返回?