Reputation: 336
I have the following class hierarchy:
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){ /* ... */}
};
So my abstract class GridMetric has two derived classes, Vector and MatrixBase. My Matrix Base class has crtp style derived class MatrixND and there is a specialization of MatrixND with N=2.
Each class shall have a virtual function getNeighbors to return a MatrixND<2,T> pointer.
It all works fine, except the MatrixND class complains that MatrixND<2,T> is an invalid covariant return type:
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){
My first question is why and how can I deal with that? Since MatrixND<2,T> inherits from MatrixBase!
My second question: Is it bad design, because I would always return raw pointers? I read the expression return new obj.. a lot, but also that this is apparently bad design. Are there other possibilities to achieve the same?
Edit: So, after some time, I realized, that the original plan wasn't going to work out and I found a much easier solution by templating the class, where I want to use those classes.
Anyway, the question stands, why the specialized MatrixND class can not be a covarient return type in the general MatrixND class. I didn't find anything saying it isn't allowed.
Upvotes: 0
Views: 103
Reputation: 3849
MatrixND<2,T>
, basic case, no need for an explanation.Vector<T>
inherits from GridMetric<T>
, so anything deriving from GridMetric<T>
(including MatrixND<2,T>
here) is fine.But, the general form MatrixND<N,T>
(N
!= 2) inherits from MatrixBase<N,T,MatrixND<N,T>>
which redefines the virtual function as:
virtual MatrixBase<N,T,Derived>* getNeighbors(T value){return nullptr;}
which forces the return type of MatrixND<N,T>
to now derive (at least) from MatrixBase<N,T,MatrixND<N,T>>
.
Not from GridMetric<T>
(as for Vector<T>
) or MatrixBase<2,T,MatrixND<2,T>>
(as for the specialization MatrixND<2,T>
), but: MatrixBase<N,T,MatrixND<N,T>>
, with (N
!= 2).
And why this is not a covariant return type? Because MatrixND<2,T>
does not inherit from MatrixBase<N,T,MatrixND<N,T>>
when N
!= 2.
Either remove the function redefinition within MatrixBase<N,T,MatrixND<N,T>>
or change its return type to GridMetric<T>
, and this will work (as MatrixND<2,T>
inherits from GridMetric<T>
).
Upvotes: 1