簡體   English   中英

繼承的運算符重載不適用於派生類

[英]Inherited operator overloads not working on derived classes

我編寫了一些代碼,這些代碼設法混合了類模板,類繼承和運算符重載,但我不知道如何解決有關運算符使用的問題。 我有一個包含大量代碼的基類(尤其是運算符重載實現和數據持有者):

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

我重載了標量和類參數的運算符。 然后,我還有一個額外的類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;
};

但是,當實例化這些類時,我只能調用標量運算符,例如將*=與兩個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對象,則它會編譯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)

}

因此,顯然,運算符重載不適用於派生類,正確的語法是什么?

編輯:我已經意識到問題在於多個運算符重載。 由於某種原因,如果我只聲明運算符以將baseMatrix對象作為參數,則可以編譯,反之亦然。

因此,對於M1*=M2 ,過載解析檢查以查看operator*=(M1, M2)和/或M1.operator*=(M2)是否可能。 沒有適合非成員operator*=候選人。 由於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

下一步是嘗試推斷過載集中的每個模板的模板參數。 兩者都成功:對於模板#1,僅采用_input_type = matrix2D<float>找到有效的專業化:

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]一個float_val一個matrix2D<float> ,這沒有意義,從而導致錯誤。

一種解決方案是使用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