Проблемы с созданием шаблона класса SquareMatrix - PullRequest
0 голосов
/ 14 марта 2020

Я пытаюсь построить шаблонный класс SquareMatrix, используя конструктор, который принимает 4 параметра в качестве 4 подматриц a, b, c, d, занимающих четыре квадранта (a = северо-запад, b = северо-восток, c = юго-запад, d = юго-восток) матрицы. Ниже показано:

    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.getA().getA() для первого доступа к M_1A, а затем для доступа к 1, вложенному в него, но вместо этого на выходе отображается большое число, которое постоянно изменяется, возможно, адрес? (в прошлый раз я попробовал это дало 6684672). Есть ли способ реализовать класс матрицы таким образом?

(EDIT: теперь включены оператор присваивания и деструктор, вероятные источники ошибки)

Ответы [ 2 ]

0 голосов
/ 15 марта 2020

Комментарии Павла прямо на отметке. Хотя ваш SquareMatrix не является встроенным, он объявлен состоящим из 4 элементов типа T. Копия по умолчанию c 'для вашего класса будет использовать оператор присваивания или присвоение c' фактического типа что T представляет в вашем использовании.

У меня есть несколько предложений по улучшению кода:

  1. Если T относится к типу, который имеет объем памяти, который больше, чем указатель / int: более эффективно позволить вашему c 'tor получить ссылку на bij const элементов следующим образом:
    SquareMatrix( const T& _a, const T& _b, const T& _c, const T& _d)
Максимально используйте конструкторы копирования: таким образом, четыре элемента сначала не инициализируются, а затем назначаются позже. Вместо этого они сразу инициализируются правильными значениями.
     SquareMatrix( const T& _a, const T& _b, const T& _c, const T& _d)
     : a( _a), b( _b), c( _c), d( _d)
     { /* empty body */ }
Выбирайте свои имена мудро, чтобы упростить вещи. Не вводите дополнительные сопоставления в схемах имен, когда это не нужно; это просто создает возможность ускользнуть. Я уже применил это в пункте 1 выше: -). Не «программируйте путем желаемого мышления»: запись в комментариях или именах типов / переменных о том, что что-то должно быть чем-то, не сделает его таким. В вашем случае: ваш класс - это НЕ квадратная матрица и даже не матрица. Для компилятора это тип данных, состоящий из четырех элементов с именами a, b, c и d соответственно типа T, который должен быть определен во время компиляции.
0 голосов
/ 15 марта 2020

Как указано в комментариях, неисправен оператор присваивания.

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 в шаблоне, чтобы иметь правильную семантику копирования, ваш класс работал бы правильно.

...