C ++重载运算符返回派生类对象而不是基类

时间:2017-04-29 17:59:07

标签: c++ templates inheritance operator-overloading derived-class

假设我有一个模板类,其中我重载了一个运算符,让我们说一个乘法运算符:

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;
  }
}

然后我使用专门的模板参数定义派生类:

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

public:


}

根据我的理解,由于运算符是在派生类中继承的,因此可以创建CMATRIX类型的对象并将其乘以复数。我期望获得的是CMATRIX类型的另一个对象。我实际得到的是基类类型的对象(带有替换的模板参数) base_matrix< complex<double> >。这有点清楚 - 派生对象调用基类方法,该方法返回基类对象。

当然,我可以在派生类中进行显式转换:

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

但它似乎是对操作符重载的不必要的重新定义。那就是 - 如果我需要显式重新定义派生类中的所有运算符重载 - 在基类中定义它们的重点是什么?

所以,这是我的一个问题。另一个更技术性的 - 如何让派生类运算符在没有显式转换的情况下返回正确(派生)类?

1 个答案:

答案 0 :(得分:3)

不是一个很好的解决方案,但......

您可以在模板基类中插入friend运算符,该模板基类的模板参数是派生类(CRTP样式)。

一个例子

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