繁体   English   中英

嵌套迭代器和接口中的“无效协变量返回类型”错误

[英]'invalid covariant return type' error in nested iterators and inteface

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

编辑:我从您当前的答案中了解到我的设计无效。 因此,有人可以针对我的问题提出更好的设计/解决方案吗? 在“矩阵”上进行迭代,该矩阵可以是“ RegMatrix”的实例(通过用于保存数据的Map实现),也可以是“ OthMatrix”的实例(通过Vector实现)。 这两个有不同的迭代器,我想一个包装迭代器来包装这两个,以便实例的类型对用户透明。 谢谢。

类矩阵(接口):

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;
};

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

第10.3.7节

覆盖函数的返回类型应与覆盖函数的返回类型相同或与函数的类协变。 如果函数D :: f覆盖函数B :: f,则函数的返回类型如果满足以下条件,则它们是协变的:

  • 都是类的指针,都是类的左值引用,或者都是类的右值引用
  • B :: f的返回类型中的类与D :: f的返回类型中的类相同,或者是D :: f的返回类型中的类的明确且可访问的直接或间接基类。 F
  • 指针或引用都具有相同的cv-qualification,并且D :: f的返回类型中的类类型具有与b :: f的返回类型中的类类型相同或更少的cv-qualification。

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

您可以使用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;
};

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

仅当返回指针或引用(相应地返回基类和派生类)时才允许使用协变返回类型,而不是按值返回时。

考虑一下-调用者需要知道要保留多少内存来存储返回值。 但是sizeof(RegMatrix::iterator) > sizeof(Matrix::iterator) 仅拥有Matrix*指针的调用方应该如何知道其中的begin()调用将返回?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM