我正在尝试创建一个名为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;
};
答案 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()
调用将返回?