假设我有一个模板类,其中我重载了一个运算符,让我们说一个乘法运算符:
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);
}
但它似乎是对操作符重载的不必要的重新定义。那就是 - 如果我需要显式重新定义派生类中的所有运算符重载 - 在基类中定义它们的重点是什么?
所以,这是我的一个问题。另一个更技术性的 - 如何让派生类运算符在没有显式转换的情况下返回正确(派生)类?
答案 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, "!!");
}