Загрузка данных


#include <iostream>
#include <stdexcept>
#include <utility>

using namespace std;

class Matrix;

// ======================================================
//                       VECTOR
// ======================================================

class Vector {
protected:
    int size;
    int* data;

public:

    // Конструктор по умолчанию
    Vector()
        : size(0), data(nullptr)
    {
    }


    // Конструктор с параметром
    Vector(int size)
        : size(size),
          data(size > 0 ? new int[size]{} : nullptr)
    {
        if (size < 0)
            throw invalid_argument("Vector size cannot be negative");
    }


    // Копирующий конструктор
    Vector(const Vector& other)
        : size(other.size),
          data(other.size > 0 ? new int[other.size] : nullptr)
    {
        for (int i = 0; i < size; i++)
            data[i] = other.data[i];
    }


    // Перемещающий конструктор
    Vector(Vector&& other) noexcept
        : size(other.size),
          data(other.data)
    {
        other.size = 0;
        other.data = nullptr;
    }


    // Деструктор
    virtual ~Vector()
    {
        delete[] data;
    }


    // Копирующее присваивание
    Vector& operator=(const Vector& other)
    {
        if (this == &other)
            return *this;

        int* newData = nullptr;

        if (other.size > 0)
            newData = new int[other.size];

        for (int i = 0; i < other.size; i++)
            newData[i] = other.data[i];

        delete[] data;

        data = newData;
        size = other.size;

        return *this;
    }


    // Перемещающее присваивание
    Vector& operator=(Vector&& other) noexcept
    {
        if (this == &other)
            return *this;

        delete[] data;

        data = other.data;
        size = other.size;

        other.data = nullptr;
        other.size = 0;

        return *this;
    }


    int getSize() const
    {
        return size;
    }


    // Доступ []
    int& operator[](int i)
    {
        if (i < 0 || i >= size)
            throw out_of_range("Vector index out of range");

        return data[i];
    }


    const int& operator[](int i) const
    {
        if (i < 0 || i >= size)
            throw out_of_range("Vector index out of range");

        return data[i];
    }


    // Vector + Vector
    Vector operator+(const Vector& other) const
    {
        if (size != other.size)
            throw invalid_argument("Vectors have different sizes");

        Vector result(size);

        for (int i = 0; i < size; i++)
            result[i] = data[i] + other[i];

        return result;
    }


    // Vector - Vector
    Vector operator-(const Vector& other) const
    {
        if (size != other.size)
            throw invalid_argument("Vectors have different sizes");

        Vector result(size);

        for (int i = 0; i < size; i++)
            result[i] = data[i] - other[i];

        return result;
    }


    // +=
    Vector& operator+=(const Vector& other)
    {
        if (size != other.size)
            throw invalid_argument("Vectors have different sizes");

        for (int i = 0; i < size; i++)
            data[i] += other[i];

        return *this;
    }


    // -=
    Vector& operator-=(const Vector& other)
    {
        if (size != other.size)
            throw invalid_argument("Vectors have different sizes");

        for (int i = 0; i < size; i++)
            data[i] -= other[i];

        return *this;
    }


    // Vector * число
    Vector operator*(int k) const
    {
        Vector result(size);

        for (int i = 0; i < size; i++)
            result[i] = data[i] * k;

        return result;
    }


    // *= число
    Vector& operator*=(int k)
    {
        for (int i = 0; i < size; i++)
            data[i] *= k;

        return *this;
    }


    // <<
    friend ostream& operator<<(ostream& out, const Vector& v)
    {
        out << "[ ";

        for (int i = 0; i < v.size; i++)
            out << v.data[i] << " ";

        out << "]";

        return out;
    }
};


// ======================================================
//                       MATRIX
// ======================================================

class Matrix : public Vector {
private:
    int rows;
    int cols;

public:

    // Конструктор по умолчанию
    Matrix()
        : Vector(),
          rows(0),
          cols(0)
    {
    }


    // Конструктор с параметрами
    Matrix(int rows, int cols)
        : Vector(rows * cols),
          rows(rows),
          cols(cols)
    {
        if (rows < 0 || cols < 0)
            throw invalid_argument("Matrix sizes cannot be negative");
    }


    // Копирующий конструктор
    Matrix(const Matrix& other)
        : Vector(other),
          rows(other.rows),
          cols(other.cols)
    {
    }


    // Перемещающий конструктор
    Matrix(Matrix&& other) noexcept
        : Vector(std::move(other)),
          rows(other.rows),
          cols(other.cols)
    {
        other.rows = 0;
        other.cols = 0;
    }


    // Деструктор
    ~Matrix() override = default;


    // Копирующее присваивание
    Matrix& operator=(const Matrix& other)
    {
        if (this == &other)
            return *this;

        Vector::operator=(other);

        rows = other.rows;
        cols = other.cols;

        return *this;
    }


    // Перемещающее присваивание
    Matrix& operator=(Matrix&& other) noexcept
    {
        if (this == &other)
            return *this;

        Vector::operator=(std::move(other));

        rows = other.rows;
        cols = other.cols;

        other.rows = 0;
        other.cols = 0;

        return *this;
    }


    int getRows() const
    {
        return rows;
    }


    int getCols() const
    {
        return cols;
    }


    // ==================================================
    // m[row][col]
    // ==================================================

    int* operator[](int row)
    {
        if (row < 0 || row >= rows)
            throw out_of_range("Matrix row out of range");

        return data + row * cols;
    }


    const int* operator[](int row) const
    {
        if (row < 0 || row >= rows)
            throw out_of_range("Matrix row out of range");

        return data + row * cols;
    }


    // Matrix + Matrix
    Matrix operator+(const Matrix& other) const
    {
        if (rows != other.rows || cols != other.cols)
            throw invalid_argument("Matrices have different sizes");

        Matrix result(rows, cols);

        for (int i = 0; i < size; i++)
            result.data[i] = data[i] + other.data[i];

        return result;
    }


    // Matrix - Matrix
    Matrix operator-(const Matrix& other) const
    {
        if (rows != other.rows || cols != other.cols)
            throw invalid_argument("Matrices have different sizes");

        Matrix result(rows, cols);

        for (int i = 0; i < size; i++)
            result.data[i] = data[i] - other.data[i];

        return result;
    }


    // Matrix * Matrix
    Matrix operator*(const Matrix& other) const
    {
        if (cols != other.rows)
            throw invalid_argument("Matrices cannot be multiplied");

        Matrix result(rows, other.cols);

        for (int i = 0; i < rows; i++)
        {
            for (int j = 0; j < other.cols; j++)
            {
                for (int k = 0; k < cols; k++)
                {
                    result[i][j] +=
                        (*this)[i][k] * other[k][j];
                }
            }
        }

        return result;
    }


    // +=
    Matrix& operator+=(const Matrix& other)
    {
        *this = *this + other;
        return *this;
    }


    // -=
    Matrix& operator-=(const Matrix& other)
    {
        *this = *this - other;
        return *this;
    }


    // *= Matrix
    Matrix& operator*=(const Matrix& other)
    {
        *this = *this * other;
        return *this;
    }


    // Matrix * число
    Matrix operator*(int k) const
    {
        Matrix result(*this);

        for (int i = 0; i < result.size; i++)
            result.data[i] *= k;

        return result;
    }


    // *= число
    Matrix& operator*=(int k)
    {
        for (int i = 0; i < size; i++)
            data[i] *= k;

        return *this;
    }


    // <<
    friend ostream& operator<<(ostream& out, const Matrix& m)
    {
        for (int i = 0; i < m.rows; i++)
        {
            for (int j = 0; j < m.cols; j++)
                out << m[i][j] << " ";

            out << '\n';
        }

        return out;
    }
};


// ======================================================
//              VECTOR * VECTOR
// ======================================================

// Скалярное произведение
long long operator*(const Vector& a, const Vector& b)
{
    if (a.getSize() != b.getSize())
        throw invalid_argument("Vectors have different sizes");

    long long result = 0;

    for (int i = 0; i < a.getSize(); i++)
        result += 1LL * a[i] * b[i];

    return result;
}


// ======================================================
//              MATRIX * VECTOR
// ======================================================

Vector operator*(const Matrix& m, const Vector& v)
{
    if (m.getCols() != v.getSize())
        throw invalid_argument(
            "Matrix and vector cannot be multiplied"
        );

    Vector result(m.getRows());

    for (int i = 0; i < m.getRows(); i++)
    {
        for (int j = 0; j < m.getCols(); j++)
        {
            result[i] += m[i][j] * v[j];
        }
    }

    return result;
}


// ======================================================
//              VECTOR * MATRIX
// ======================================================

Vector operator*(const Vector& v, const Matrix& m)
{
    if (v.getSize() != m.getRows())
        throw invalid_argument(
            "Vector and matrix cannot be multiplied"
        );

    Vector result(m.getCols());

    for (int j = 0; j < m.getCols(); j++)
    {
        for (int i = 0; i < m.getRows(); i++)
        {
            result[j] += v[i] * m[i][j];
        }
    }

    return result;
}


// ======================================================
//              NUMBER * VECTOR
// ======================================================

Vector operator*(int k, const Vector& v)
{
    return v * k;
}


// ======================================================
//              NUMBER * MATRIX
// ======================================================

Matrix operator*(int k, const Matrix& m)
{
    return m * k;
}


// ======================================================
//        ПРОВЕРКА ВОЗМОЖНОСТИ СЛОЖЕНИЯ
// ======================================================

// Vector + Vector
bool canAdd(const Vector& a, const Vector& b)
{
    return a.getSize() == b.getSize();
}


// Vector + Matrix
bool canAdd(const Vector&, const Matrix&)
{
    return false;
}


// Matrix + Vector
bool canAdd(const Matrix&, const Vector&)
{
    return false;
}


// Matrix + Matrix
bool canAdd(const Matrix& a, const Matrix& b)
{
    return
        a.getRows() == b.getRows()
        &&
        a.getCols() == b.getCols();
}


// ======================================================
//       ПРОВЕРКА ВОЗМОЖНОСТИ УМНОЖЕНИЯ
// ======================================================

// Vector * Vector
bool canMultiply(const Vector& a, const Vector& b)
{
    return a.getSize() == b.getSize();
}


// Vector * Matrix
bool canMultiply(const Vector& v, const Matrix& m)
{
    return v.getSize() == m.getRows();
}


// Matrix * Vector
bool canMultiply(const Matrix& m, const Vector& v)
{
    return m.getCols() == v.getSize();
}


// Matrix * Matrix
bool canMultiply(const Matrix& a, const Matrix& b)
{
    return a.getCols() == b.getRows();
}


// ======================================================
//                       MAIN
// ======================================================

int main()
{
    try
    {
        // ==============================================
        // ВЕКТОРЫ
        // ==============================================

        Vector v1(3);

        v1[0] = 1;
        v1[1] = 2;
        v1[2] = 3;


        Vector v2(3);

        v2[0] = 4;
        v2[1] = 5;
        v2[2] = 6;


        cout << "v1 = " << v1 << '\n';
        cout << "v2 = " << v2 << '\n';

        cout << "v1 + v2 = "
             << v1 + v2 << '\n';

        cout << "v1 - v2 = "
             << v1 - v2 << '\n';

        cout << "v1 * v2 = "
             << v1 * v2 << '\n';

        cout << "v1 * 3 = "
             << v1 * 3 << '\n';

        cout << '\n';


        // ==============================================
        // МАТРИЦА A 2x3
        // ==============================================

        Matrix a(2, 3);

        a[0][0] = 1;
        a[0][1] = 2;
        a[0][2] = 3;

        a[1][0] = 4;
        a[1][1] = 5;
        a[1][2] = 6;


        // ==============================================
        // МАТРИЦА B 3x2
        // ==============================================

        Matrix b(3, 2);

        b[0][0] = 1;
        b[0][1] = 2;

        b[1][0] = 3;
        b[1][1] = 4;

        b[2][0] = 5;
        b[2][1] = 6;


        cout << "A:\n";
        cout << a << '\n';

        cout << "B:\n";
        cout << b << '\n';


        // Matrix * Matrix
        cout << "A * B:\n";
        cout << a * b << '\n';


        // ==============================================
        // MATRIX * VECTOR
        // ==============================================

        Vector x(3);

        x[0] = 1;
        x[1] = 2;
        x[2] = 3;

        cout << "A * x = "
             << a * x << '\n';


        // ==============================================
        // VECTOR * MATRIX
        // ==============================================

        Vector y(2);

        y[0] = 10;
        y[1] = 20;

        cout << "y * A = "
             << y * a << '\n';


        // ==============================================
        // КОПИРОВАНИЕ
        // ==============================================

        Matrix c = a;

        cout << "\nCopy of A:\n";
        cout << c;


        // ==============================================
        // ПЕРЕМЕЩЕНИЕ
        // ==============================================

        Matrix moved = std::move(c);

        cout << "\nMoved matrix:\n";
        cout << moved;


        // ==============================================
        // ПРОВЕРКИ
        // ==============================================

        cout << boolalpha;

        cout << "\nCan add v1 and v2: "
             << canAdd(v1, v2) << '\n';

        cout << "Can add v1 and A: "
             << canAdd(v1, a) << '\n';

        cout << "Can multiply A and B: "
             << canMultiply(a, b) << '\n';

        cout << "Can multiply A and x: "
             << canMultiply(a, x) << '\n';
    }

    catch (const exception& e)
    {
        cout << "Error: "
             << e.what() << '\n';
    }

    return 0;
}