简体   繁体   中英

C++ overloaded operator to return the derived class object not the base class

Say I have a template class in which I overload one of the operators, lets say a 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 specialized template parameter:

class CMATRIX : public base_matrix< complex<double> >{

public:


}

In my understanding, since the operators are inherited in the derived class, one can create an object of type CMATRIX and multiply it by a complex number. What I expect to get is another object of the type CMATRIX. What I actually get is the object of the base class type (with the substituted template argument) base_matrix< complex<double> > . This is kinda clear - the derived object calls the base class method, which returns the base class object.

Sure, I could do an explicit conversion in the derived class:

friend CMATRIX operator*(const CMATRIX& ob, const complex<double>& f){     
  return CMATRIX(ob * f);
}

but it seems like an unnecessary redefinition of the operator overload. That is - if I need to explicitly redefine all the operator overloads in the derived class - what is the point of defining them in the base class?

So, this is one of my questions. Another, more technical - how do I actually make the derived class operator return the right (derived) class without explicit conversion?

Not a great solution but...

You can insert the friend operator in a template base class that whose template argument is the derived class (CRTP style).

An 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, "!!");
 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM