Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/155.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ ';无效的协变返回类型';嵌套迭代器和接口中出错_C++_Iterator_Nested - Fatal编程技术网

C++ ';无效的协变返回类型';嵌套迭代器和接口中出错

C++ ';无效的协变返回类型';嵌套迭代器和接口中出错,c++,iterator,nested,C++,Iterator,Nested,我正在尝试创建一个名为Matrix的接口。两个类将实现这个接口。 其中之一称为正则矩阵(regularmatrix)。 现在,我正在尝试为类RegMatrix和OthMatrix构建迭代器,让用户能够迭代“Matrix”对象。 问题是,对于begin()和end()方法,我得到了一个错误“virtual RegMatrix::iterator RegMatrix::begin()”的无效协变返回类型,可能是因为其中一个返回RegMatrix::iterator,而基函数返回Matrix::ite

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

编辑: 我从你目前的回答中了解到我的设计是无效的。那么,有人能为我的问题提出更好的设计/解决方案吗?在“矩阵”上迭代,该矩阵可能是“RegMatrix”的一个疯狂部分(使用映射来保存数据),也可能是“OthMatrix”的一个实例(使用向量实现)。这两个有不同的迭代器,我需要一个包装迭代器来包装这两个迭代器,这样在迭代时,实例的类型对用户是透明的。谢谢

类矩阵(接口):

类正则矩阵:

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

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


想想看——调用者需要知道为存储返回值保留了多少内存。但是
sizeof(RegMatrix::iterator)>sizeof(Matrix::iterator)
。只有
Matrix*
指针在手的调用方如何知道它们中的哪个
begin()
调用将返回?

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

§10.3.7

重写函数的返回类型应与 重写函数的返回类型或与 函数的类。如果函数D::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;
};
#包括
类矩阵
{
公众:
类迭代器
{
公众:
//这是迭代器正在使用的实现的接口
结构impl
{
虚拟~impl(){}
虚拟双解引用()常量=0;
// [...]
};
//构造函数接受一个实现
迭代器(std::unique_ptr impl)
:m_impl{std::move(impl)}
{
}
双运算符*()常数
{
//所有调用都涉及到具体的实现
返回m_impl->dereference();
}
// [...]
私人:
std::唯一的\u ptr m\u impl;
};
虚拟迭代器begin()=0;
虚拟迭代器end()=0;
};
类RegMatrix:公共矩阵
{
//每个矩阵都有自己的迭代器实现
类迭代器_impl:public Matrix::迭代器::impl
{
公众:
迭代器(向量2D::迭代器itr)
:m_itr{itr}
{
}
虚拟双解引用()常量重写
{
返回*m_itr;
}
// [...]
私人:
向量2D::迭代器m_itr;
};
虚拟迭代器begin()重写
{
//返回保存迭代器实现的迭代器
返回迭代器(std::unique_ptr{new iterator_impl{matrix.begin()}});
}
虚拟迭代器end()重写
{
返回迭代器(std::unique_ptr{new iterator_impl{matrix.end()}});
}
私人:
矢量二维矩阵;
};

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

要解决语法错误,您不能返回指针或引用。但您可以看到,还有另一个问题。我认为您应该重新考虑您的设计。我理解。那么,有人能为我的问题提出更好的设计/解决方案吗?在“矩阵”上迭代,该矩阵可能是“RegMatrix”的一个疯狂部分(使用映射来保存数据),也可能是“OthMatrix”的一个实例(使用向量实现)。这两个有不同的迭代器,我需要一个包装迭代器来包装这两个迭代器,这样在迭代时,实例的类型对用户是透明的。谢谢。有关替代设计方法,请参见我编辑的答案。
#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;
};