【问题标题】:Inherited operator overloads not working on derived classes继承的运算符重载不适用于派生类
【发布时间】:2018-07-03 00:59:56
【问题描述】:

我编写了一些代码,设法混合了类模板、类继承和运算符重载,但我不知道如何解决有关运算符使用的问题。我有一个包含大量代码的基类(特别是运算符重载实现和数据持有者):

template <typename _type> 
class baseMatrix {
public:
    baseMatrix();
    ~baseMatrix();

    //operators 
    baseMatrix<_type>& operator= (baseMatrix<_type> _mat);
    template <typename _input_type> baseMatrix<_type>& operator*= (_input_type _val);
    template <typename _input_type> baseMatrix<_type>& operator/= (_input_type _val); 
    template <typename _input_type> baseMatrix<_type>& operator+= (_input_type _val); 
    template <typename _input_type> baseMatrix<_type>& operator-= (_input_type _val);
    template <typename _input_type> baseMatrix<_type>& operator*= (const baseMatrix<_input_type>& _mat);
    template <typename _input_type> baseMatrix<_type>& operator/= (const baseMatrix<_input_type>& _mat);
    template <typename _input_type> baseMatrix<_type>& operator+= (const baseMatrix<_input_type>& _mat);
    template <typename _input_type> baseMatrix<_type>& operator-= (const baseMatrix<_input_type>& _mat);        

protected:
    std::vector<_type> data;
};

/* ... */
template <typename _type>
template <typename _input_type> 
baseMatrix<_type>& baseMatrix<_type>::operator*=(_input_type _val) { 
    for (int i = 0; i < data.size(); ++i) data[i]*=_val; 
    return *this;
};
template <typename _type>
template <typename _input_type> 
baseMatrix<_type>& baseMatrix<_type>::operator*=(const baseMatrix<_input_type>& _mat) { 
    for (int i = 0; i < data.size(); ++i) data[i]*=_mat.data[i]; 
    return *this;
};
/* remaining operator overload functions */

我为标量和类参数重载了运算符。然后我有一个额外的类matrix2DbaseMatrix 继承这些运算符:

template <typename _type> 
class matrix2D : public baseMatrix<_type> {
public:
    matrix2D(int _rows, int _cols);
    matrix2D(int _rows, int _cols, _type _val);
    ~matrix2D();

    _type& operator()(int _r, int _c); 
    _type& at(int _r, int _c);

protected:
    int nRows,nCols;
    using baseMatrix<_type>::data;
};

但是,在实例化这些类时,我只能调用标量运算符,例如使用*= 带有两个 matrix2D 对象会导致编译错误:

In file included from test.cpp:1:
baseMatrix.hpp: In instantiation of ‘baseMatrix<_type>& baseMatrix<_type>::operator*=(_input_type) [with _input_type = matrix2D<float>; _type = float]’:
test.cpp:29:6:   required from here
baseMatrix.hpp:56:47: error: no match for ‘operator*=’ (operand types are ‘__gnu_cxx::__alloc_traits<std::allocator<float>, float>::value_type’ {aka ‘float’} and ‘matrix2D<float>’)
for (int i = 0; i < data.size(); ++i) data[i]*=_val;

另一方面,如果我实例化一个 baseMatrix 对象,它可以编译(由于其他原因在运行时失败,即未初始化数据):

int main(int argc, char const *argv[]){
    matrix2D<float> M1(5,5,0.0);
    matrix2D<float> M2(3,3,6.0);
    baseMatrix<float> testM;

    M2*=0.47;   // works
    M2*=M1;     // does not compile
    M2*=testM  // runtime error (segfault)

}

显然,运算符重载不适用于派生类,正确的语法是什么?

编辑:我意识到问题在于多个运算符重载。出于某种原因,如果我只声明运算符以 baseMatrix 对象作为参数,则它能够编译,反之亦然。

【问题讨论】:

  • 离题,但你真的不应该用下划线开始标识符。
  • 提示 - 您定义了如何将矩阵乘以浮点数,而不是浮点数乘以矩阵,您的代码正在这样做。
  • @PaulMcKenzie 你这是什么意思?
  • 您的代码正在执行以下操作:data[i] *= _val。简而言之float *= matrix。哪一个重载与该调用匹配?

标签: c++ templates inheritance operator-overloading


【解决方案1】:

因此对于M1*=M2,重载决议检查operator*=(M1, M2) 和/或M1.operator*=(M2) 是否可能。非会员operator*= 没有好的候选人。由于M1 具有继承baseMatrix&lt;float&gt; 的类型matrix2D&lt;float&gt;,因此编译器会看到M1 具有成员函数:

template <typename _input_type> baseMatrix<float>& operator*= (_input_type _val); // #1
template <typename _input_type> baseMatrix<float>& operator*= (const baseMatrix<_input_type>& _mat); // #2

下一步是尝试为重载集中的每个模板推断模板参数。两者都成功:对于模板 #1,它仅通过 _input_type = matrix2D&lt;float&gt; 找到一个有效的特化:

baseMatrix<float>& baseMatrix<float>::operator*=<matrix2D<float>>(matrix2D<float> _val); // #3

对于模板#2,它通过使用M2 参数类型的基类并确定_input_type = float 来找到特化:

baseMatrix<float>& baseMatrix<float>::operator*=<float>(const baseMatrix<float>& _val); // #4

然后比较这些函数模板特化。这里的问题是您打算使用#4,但#3 被认为比#4 更好的匹配,因为#3 使用参数M2 的确切类型,但#4 需要派生到基础的转换。然后#3 的实例化包含语句data[i]*=_val;,这对于data[i] a float_val a matrix2D&lt;float&gt; 没有意义,从而导致错误。

一种解决方案是使用 SFINAE 技术来确保模板 #1 不能与矩阵类型一起使用:

#include <utility>
#include <type_traits>

template <typename Type>
class baseMatrix {
private:
    template <typename ValType>
    static constexpr std::true_type is_matrix_ptr(const baseMatrix<ValType>*);
    static constexpr std::false_type is_matrix_ptr(const void*);

public:
    // ...
    template <typename ScalarType,
              std::enable_if_t<!decltype(is_matrix_ptr(std::declval<ScalarType*>()))
                  ::value>* = nullptr>
    baseMatrix& operator*=(ScalarType val);
    // ...
};

【讨论】:

    猜你喜欢
    • 2018-07-09
    • 1970-01-01
    • 2012-02-12
    • 2020-08-02
    • 1970-01-01
    • 2011-12-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多