C++ ';无效的协变返回类型';嵌套迭代器和接口中出错
我正在尝试创建一个名为Matrix的接口。两个类将实现这个接口。 其中之一称为正则矩阵(regularmatrix)。 现在,我正在尝试为类RegMatrix和OthMatrix构建迭代器,让用户能够迭代“Matrix”对象。 问题是,对于begin()和end()方法,我得到了一个错误“virtual RegMatrix::iterator RegMatrix::begin()”的无效协变返回类型,可能是因为其中一个返回RegMatrix::iterator,而基函数返回Matrix::iterator。我不明白这到底是怎么回事。有人知道如何解决这个问题吗? 谢谢 编辑: 我从你目前的回答中了解到我的设计是无效的。那么,有人能为我的问题提出更好的设计/解决方案吗?在“矩阵”上迭代,该矩阵可能是“RegMatrix”的一个疯狂部分(使用映射来保存数据),也可能是“OthMatrix”的一个实例(使用向量实现)。这两个有不同的迭代器,我需要一个包装迭代器来包装这两个迭代器,这样在迭代时,实例的类型对用户是透明的。谢谢 类矩阵(接口): 类正则矩阵:C++ ';无效的协变返回类型';嵌套迭代器和接口中出错,c++,iterator,nested,C++,Iterator,Nested,我正在尝试创建一个名为Matrix的接口。两个类将实现这个接口。 其中之一称为正则矩阵(regularmatrix)。 现在,我正在尝试为类RegMatrix和OthMatrix构建迭代器,让用户能够迭代“Matrix”对象。 问题是,对于begin()和end()方法,我得到了一个错误“virtual RegMatrix::iterator RegMatrix::begin()”的无效协变返回类型,可能是因为其中一个返回RegMatrix::iterator,而基函数返回Matrix::ite
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;
};