我有以下类层次结构:

template<typename T>
class GridMetric{
  virtual GridMetric* getNeighbors(T value) = 0;
};

template<size_t N, typename T, typename Derived>
class MatrixBase : public GridMetric<T>{
  virtual MatrixBase<N,T,Derived>* getNeighbors(T value){return nullptr;}
};

template<size_t N, typename T>
class MatrixND : public MatrixBase<N,T,MatrixND<N,T>>{
  virtual MatrixND<2,T>* getNeighbors(T value){ /* ... */}
};

template<typename T>
class MatrixND<2,T> : public MatrixBase<2,T,MatrixND<2,T>>{
  virtual MatrixND<2,T>* getNeighbors(T value){ /* ... */}
};

template<typename T>
class Vector : public GridMetric<T>{
  virtual MatrixND<2,T>* getNeighbors(T value){ /* ... */}
};


因此,我的抽象类GridMetric具有两个派生类,即Vector和MatrixBase。我的Matrix Base类具有crtp样式派生的类MatrixND,并且具有N = 2的MatrixND专业化。

每个类都应具有一个虚函数getNeighbors以返回MatrixND 指针。

一切正常,除了MatrixND类抱怨MatrixND 是无效的协变量返回类型:

error: invalid covariant return type for ‘MatrixND<2ul, T>* MatrixND<N, T>::getNeighbors(T&) [with long unsigned int N = 3ul; T = double]’
  virtual MatrixND<2,T>* getNeighbors(T& in){


我的第一个问题是为什么以及如何处理?由于MatrixND 继承自MatrixBase!

我的第二个问题:设计不好,因为我总是会返回原始指针吗?我读了很多返回新obj ..的表达式,但是这显然是错误的设计。还有其他实现相同目标的可能性吗?

编辑:所以,过了一段时间,我意识到原来的计划是不会制定出来的,并且我通过在我想使用这些类的模板上进行模板化找到了一个更简单的解决方案。

无论如何,问题仍然存在,为什么专用MatrixND类不能在常规MatrixND类中成为协变返回类型。我没有发现任何禁止的信息。

最佳答案

MatrixND<2,T>,基本情况,无需解释。
Vector<T>继承自GridMetric<T>,所以任何从GridMetric<T>派生的内容(此处包括MatrixND<2,T>)都可以。


但是,一般形式MatrixND<N,T>N!= 2)继承自MatrixBase<N,T,MatrixND<N,T>>,其将虚拟函数重新定义为:

virtual MatrixBase<N,T,Derived>* getNeighbors(T value){return nullptr;}


这迫使MatrixND<N,T>的返回类型现在(至少)从MatrixBase<N,T,MatrixND<N,T>>派生。
不是来自GridMetric<T>(对于Vector<T>)还是MatrixBase<2,T,MatrixND<2,T>>(对于专业化MatrixND<2,T>),而是:MatrixBase<N,T,MatrixND<N,T>>,带有(N!= 2)。

为什么这不是协变返回类型?因为当MatrixND<2,T>!= 2时MatrixBase<N,T,MatrixND<N,T>>不会从N继承。

删除MatrixBase<N,T,MatrixND<N,T>>中的函数重定义或将其返回类型更改为GridMetric<T>,这将起作用(因为MatrixND<2,T>继承自GridMetric<T>)。

09-06 11:44