schrödinbug
schrödinbug

Reputation: 863

Base class method return derived class objec

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

Answers (2)

Manu343726
Manu343726

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

Muhammad Faizan
Muhammad Faizan

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

Related Questions