An overloaded C ++ operator returns a derived class object, not a base class
Let's say I have a template class in which I overload one of the operators, let's say the multiplication operator:
template <typename T1>
class base_matrix{
public:
T1* M;
....
base_matrix<T1>& operator*=(const complex<double>& f){
for(int i=0;i<n_elts;i++) { M[i] *= (T1)f; }
return *this;
}
friend base_matrix<T1> operator*(const int& f, const base_matrix<T1>& ob){
base_matrix<T1> res(ob); res *= f; return res;
}
}
Then I define a derived class with a custom template parameter:
class CMATRIX : public base_matrix< complex<double> >{
public:
}
In my understanding, since operators are inherited in a derived class, it is possible to create an object of type CMATRIX and multiply it by a complex number. What I am expecting to get is another CMATRIX type object. I am actually getting an object of the base class type (with the overridden template argument)
base_matrix< complex<double> >
. This is understandable: a derived object calls a method of the base class, which returns an object of the base class.
Of course, I can do an explicit conversion in the derived class:
friend CMATRIX operator*(const CMATRIX& ob, const complex<double>& f){
return CMATRIX(ob * f);
}
but that looks like an unnecessary overload of operator overloading. That is - if I need to explicitly override all operator overloads in a derived class - what is the point of defining them in the base class?
So this is one of my questions. Another, more technical one - how can I get the derived class operator to return the right (derived) class without explicit conversion?
source to share
Not a great solution, but ...
You can insert a statement friend
into a template base class whose template argument is derived class (CRTP style).
Example
#include <complex>
#include <type_traits>
template <typename T>
struct multM
{
friend T operator* (int const f, T const & ob)
{ T res(ob); res *= f; return res; }
};
template <typename T1>
class base_matrix : public multM<base_matrix<T1>>
{
public:
T1 * M;
std::size_t n_elts;
base_matrix<T1>& operator*=(const std::complex<double>& f){
for(int i=0;i<n_elts;i++) { M[i] *= (T1)f; }
return *this;
}
};
class CMATRIX : public base_matrix<std::complex<double>>,
public multM<CMATRIX>
{ };
int main()
{
static_assert(std::is_same<base_matrix<float>,
decltype(int{}*base_matrix<float>{})>::value, "!");
static_assert(std::is_same<CMATRIX,
decltype(int{}*CMATRIX{})>::value, "!!");
}
source to share