简体   繁体   English

继承的运算符重载不适用于派生类

[英]Inherited operator overloads not working on derived classes

I wrote some code that manages to mix class templates, class inheritance, and operator overloading and I'm lost as to how to solve an issue regarding operator use. 我编写了一些代码,这些代码设法混合了类模板,类继承和运算符重载,但我不知道如何解决有关运算符使用的问题。 I have a base class with the bulk of the code (particularly, operator overloading implementation and data holders): 我有一个包含大量代码的基类(尤其是运算符重载实现和数据持有者):

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 */

I overloaded operators for both scalar and class arguments. 我重载了标量和类参数的运算符。 I then have and additional class matrix2D that inherits those operators from baseMatrix : 然后,我还有一个额外的类matrix2D ,它从baseMatrix继承了这些运算符:

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

However, when instantiating these classes I'm only able to call the scalar operators, as using eg *= with two matrix2D objects results in a compilation error: 但是,当实例化这些类时,我只能调用标量运算符,例如将*=与两个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;

If, on the other hand, I instantiate a baseMatrix object, it compiles OK (fails at runtime for other reasons, ie unitialized data): 另一方面,如果我实例化了baseMatrix对象,则它会编译OK(在运行时由于其他原因,即单元化数据失败):

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)

} }

So apparently the operator overload is not working for derived classes, what would be the correct syntax? 因此,显然,运算符重载不适用于派生类,正确的语法是什么?

EDIT: I've realized that the problem is with multiple operator overloads. 编辑:我已经意识到问题在于多个运算符重载。 For some reason it is able to compile if I only declare the operators to take a baseMatrix object as argument, or vice-versa. 由于某种原因,如果我只声明运算符以将baseMatrix对象作为参数,则可以编译,反之亦然。

So for M1*=M2 , overload resolution checks to see whether operator*=(M1, M2) and/or M1.operator*=(M2) are possible. 因此,对于M1*=M2 ,过载解析检查以查看operator*=(M1, M2)和/或M1.operator*=(M2)是否可能。 There are no good candidates for non-member operator*= . 没有适合非成员operator*=候选人。 Since M1 has type matrix2D<float> which inherits baseMatrix<float> , the compiler sees that M1 has member functions: 由于M1类型为matrix2D<float> ,它继承了baseMatrix<float> ,因此编译器会看到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

The next step is to attempt to deduce template arguments for each template in the overload set. 下一步是尝试推断过载集中的每个模板的模板参数。 Both succeed: For template #1, it finds a valid specialization by just taking _input_type = matrix2D<float> : 两者都成功:对于模板#1,仅采用_input_type = matrix2D<float>找到有效的专业化:

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

For template #2, it finds a specialization by using the base class of the M2 argument type and determining _input_type = float : 对于模板2,它通过使用M2参数类型的基类并确定_input_type = float来找到一种特殊化:

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

Then these function template specializations are compared. 然后比较这些功能模板的专长。 The trouble here is that you meant to use #4, but #3 is considered a better match than #4, since #3 uses the exact type of argument M2 , but #4 needs a derived-to-base conversion. 这里的问题是您打算使用#4,但是#3被认为比#4更好,因为#3使用参数M2的确切类型,但是#4需要派生到基数的转换。 Then the instantiation of #3 contains the statement data[i]*=_val; 然后#3的实例包含语句data[i]*=_val; which doesn't make sense for data[i] a float and _val a matrix2D<float> , causing the error. 对于data[i]一个float_val一个matrix2D<float> ,这没有意义,从而导致错误。

One solution is to use a SFINAE technique to make sure template #1 can't be used with a matrix type: 一种解决方案是使用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);
    // ...
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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