Reputation: 863
I'm creating a matrix class (primarily for self-imposed practice, I know about Eigen). In it I have matrix multiplication defined as one would expect- the method takes a const reference to a Matrix object and returns a Matrix object.
Matrix Matrix::operator *(const Matrix& rhs) const
{
Matrix temp(mRows,rhs.mCols);
... //do Matrix Multiplication
return temp;
}
I then derive a DCM class (Direction Cosine Matrix--just a special kind of matrix).
class DCM: public Matrix
{
.... // class definition here, but does NOT contain definition for
// matrix multiplication
};
I can create two DCM objects and multiply them together no problem, but the object returned is of type Matrix.
DCM Rvb_q(q);
DCM Rvb_p(p);
DCM Rvb_pq(Rvb_p*Rvb_q); // error because Rvb_p*Rvb_q returns a Matrix object
Is there way to have that function return a DCM object without having to recode the function in the derived class? One way is to add this constructor to the derived class:
DCM(const Matrix &M):Matrix(M) {}
But that seems really inefficient (creates a new object for the multiplication and then copies it when making the DCM object) and limiting (Anytime I multiplied two DCM objects together, I'd have to create a new DCM object for the Matrix object to be copied into--I couldn't just use the returned object as a DCM). Is there a way to reuse the base class function, but have it return the derived class type?
Upvotes: 2
Views: 1591
Reputation: 14174
You could achieve that using the Curiously Recurrent Template Pattern. The CRTP is an idiom where a class inherits from a template class with it as template argumment. For example:
template<typename T>
struct CRTP_base {};
struct foo : public CRTP_base<foo> {};
The power of this idiom relays in the fact that the base class knows what class derives from it. You could use that property to solve your problem:
template<typename T>
struct matrix_base
{
T& operator*=(const T& rhs)
{
/* Multiplication code */
return static_cast<T&>(*this);
}
};
struct DCM : public matrix_base<DCM> {};
int main()
{
DCM a,b c;
a *= b; //OK, call to matrix_base<DCM>::operator*, which expects a DCM as parameter,
//and returns a reference to a DCM.
}
Upvotes: 2
Reputation: 944
If anything that inherits from matrix multiplies to the same type (is closed under multiplication), then you can hack together something like:
template <class TMatrix>
TMatrix Matrix::operator *(const TMatrix& rhs)
{
TMatrix temp(mRows, rhs.mCols);
// multiply
return temp;
}
But I don't recommend that. In cases like these I think it's better to be explicit that multiplying a DCM by a DCM results in a DCM:
DCM DCM::operator *(const DCM& rhs)
{
return Matrix::operator*(rhs);
}
in this case you should also declare (possibly private) DCM(const Matrix&) and DCM(Matrix&&)
.
Upvotes: 1