繁体   English   中英

构建 SquareMatrix 模板类的问题

[英]Problems building a SquareMatrix template class

我试图通过使用接受 4 个参数作为 4 SquareMatrix矩阵abcd占据四个象限( a = 西北, b = 东北, c = 西南, d = 东南)的构造函数来构建SquareMatrix模板类矩阵。 如下图:

    template<class T> class SquareMatrix {
    public:
        SquareMatrix(){}
        SquareMatrix(const T first, const T second, const T third, const T fourth) {
            a = first;
            b = second;
            c = third;
            d = fourth;
        }
        SquareMatrix<T>(const SquareMatrix<T>& rhs) { // copy constructor
            a = rhs.getA();
            b = rhs.getB();
            c = rhs.getC();
            d = rhs.getD();
        }
        SquareMatrix& operator=(const SquareMatrix rhs) {  // assignment operator
            if (&rhs != this) {
                SquareMatrix(rhs);
            }

            return *this;
        }
        ~SquareMatrix() {}  // destructor

        // getters and setters
        T getA() const {return a;}
        T getB() const {return b;}
        T getC() const {return c;}
        T getD() const {return d;}
        void setA(const T& input) {a = input;}
        void setB(const T& input) {b = input;}
        void setC(const T& input) {c = input;}
        void setD(const T& input) {d = input;}

    private:   
        // 4 quadrants
        // [a, b;
        //  c, d]
        T a, b, c, d;
    };

    template<class T> SquareMatrix<T> operator+(const SquareMatrix<T> lhs, 
                      const SquareMatrix<T>& rhs) {
        SquareMatrix<T> ret(lhs);
        ret.setA( ret.getA() + rhs.getA() );
        ret.setB( ret.getB() + rhs.getB() );
        ret.setC( ret.getC() + rhs.getC() );
        ret.setD( ret.getD() + rhs.getD() );

        return ret;
    };
    template<class T> SquareMatrix<T> operator-(const SquareMatrix<T> lhs,
                      const SquareMatrix<T>& rhs) {
        SquareMatrix<T> ret(lhs);
        ret.setA( ret.getA() - rhs.getA() );
        ret.setB( ret.getB() - rhs.getB() );
        ret.setC( ret.getC() - rhs.getC() );
        ret.setD( ret.getD() - rhs.getD() );

        return ret;
    };
    // this is the implementation of Strassen's algorithm
    template<class T> SquareMatrix<T> operator*(const SquareMatrix<T>& lhs, 
                      const SquareMatrix<T>& rhs) {
        T product_1 = lhs.getA() * ( rhs.getB() - rhs.getD() );
        T product_2 = ( lhs.getA() + lhs.getB() ) * rhs.getD();
        T product_3 = ( lhs.getC() + lhs.getD() ) * rhs.getA();
        T product_4 = lhs.getD() * ( rhs.getC() - rhs.getA() );
        T product_5 = ( lhs.getA() + lhs.getD() ) * ( rhs.getA() + rhs.getD() );
        T product_6 = ( lhs.getB() - lhs.getD() ) * ( rhs.getC() + rhs.getD() );
        T product_7 = ( lhs.getA() - lhs.getC() ) * ( rhs.getA() + rhs.getB() );
        SquareMatrix<T> ret;
        ret.setA(product_5 + product_4 - product_2 + product_6);
        ret.setB(product_1 + product_2);
        ret.setC(product_3 + product_4);
        ret.setD(product_1 + product_5 - product_3 - product_7);

        return ret;
    };

现在,我正在尝试通过执行以下操作来创建嵌套的 4x4 矩阵:

    int main() {
        cout << "Example: a 4x4 matrix: " << endl;
        // 4 single quadrants 
        SquareMatrix<int> M_1A(1, 2, 3, 4);
        SquareMatrix<int> M_1B(5, 6, 7, 8);
        SquareMatrix<int> M_1C(9, 10, 11, 12);
        SquareMatrix<int> M_1D(13, 14, 15, 16);
        // 4x4 matrix M_1
        SquareMatrix< SquareMatrix<int> > M_1(M_1A, M_1B, M_1C, M_1D);
        // test
        cout << "test: " << endl;
        cout << M_1.getA().getA() << endl;

        return 0;
    }

预期的矩阵输出应为M_1 = [1,2,5,6; 3,4,7,8; 9,10,13,14; 11,12,15,16] M_1 = [1,2,5,6; 3,4,7,8; 9,10,13,14; 11,12,15,16] M_1 = [1,2,5,6; 3,4,7,8; 9,10,13,14; 11,12,15,16] 我使用M_1.getA().getA()命令首先访问M_1A ,然后访问嵌套在其中的1 ,但输出显示的是一个不断变化的大数字,也许是地址? (我上次尝试的结果是 6684672)。 有没有办法以这种方式实现矩阵类?

(编辑:现在包括赋值运算符和析构函数,可能是错误的来源)

正如评论所建议的那样,错误的是赋值运算符。

SquareMatrix& operator=(const SquareMatrix rhs) {
    if (&rhs != this) {
         SquareMatrix(rhs); // <-- This creates a temporary that 
                            // dies off after that line is executed
    }
    return *this;
}

赋值运算符不做任何赋值。 取而代之的是一个临时的SquareMatrix

要解决这个问题,要么

1) 不提供任何赋值运算符、复制构造函数或析构函数,因为类型T应该是可安全复制的。

2) 修复赋值运算符,使其正常工作:

#include <algorithm>
//...
SquareMatrix& operator=(const SquareMatrix rhs) {
    if (&rhs != this) {
         SquareMatrix t(rhs); 
         std::swap(t.a, a); 
         std::swap(t.b, b); 
         std::swap(t.c, c); 
         std::swap(t.d, d); 
    }
    return *this;
}

任务现在可以工作了。 但是,我建议不要编写不需要编写的代码,而您的错误实现就是这种情况。

在您的情况下,如果您让编译器生成赋值运算符和/或依赖模板中的T来获得正确的复制语义,您的类就会正常工作。

保罗的评论恰如其分。 尽管您的 SquareMatrix 不是内置的,但它被声明为由 4 个 T 类型的元素组成。您的类的默认复制 c'tor 将使用 T 表示的实际类型的赋值运算符或赋值 c'tor在您的使用中。

我有一些改进代码的建议:

  1. 如果 T 是一种内存占用大于指针/int 的类型:让您的 c'tor 接收元素 bij const 引用更有效,如下所示:
    SquareMatrix( const T& _a, const T& _b, const T& _c, const T& _d)
  1. 尽可能多地使用复制构造函数:这样四个元素就不会先初始化,然后再分配。 相反,它们会立即使用正确的值进行初始化。
     SquareMatrix( const T& _a, const T& _b, const T& _c, const T& _d)
     : a( _a), b( _b), c( _c), d( _d)
     { /* empty body */ }
  1. 明智地选择你的名字以简化事情。 不必要时不要在名称方案中引入额外的映射; 它只是创造了滑倒的机会。 我已经在上面的第 1 点应用了它:-)。
  2. 不要“一厢情愿地编程”:在注释或类型/变量名称中写下应该是某物的某物不会成为某物。 在您的情况下:您的班级不是方阵,甚至也不是矩阵。 对于编译器来说,它是一种数据类型,由四个元素组成,分别命名为 a、b、c 和 d,属于在编译时定义的类型 T。

暂无
暂无

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

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