Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.88/40: Рейтинг темы: голосов - 40, средняя оценка - 4.88
1 / 1 / 0
Регистрация: 03.01.2019
Сообщений: 11

Перегрузка операторов для матрицы

05.11.2019, 20:09. Показов 7671. Ответов 15

Студворк — интернет-сервис помощи студентам
Изучая перегрузки операторов столкнулся с такой проблемой:
По заданию нужно перегрузить "+", "-", "*", "=" для матриц. С присваиваниям все получилось, а вот все остальное...

Не судите строго

Matrix.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#pragma once
#include <iostream>
 
class Matrix
{
    int m_n, m_m;       // Размер матрицы
    int** m_mat;        // Указатель для матрицы
 
    void memoryAllocation(int n);
    void memoryAllocation(int n, int m);
    void deleteMatrix();
public:
 
    Matrix();
    Matrix(int n, int m, int x);
    Matrix(int n, int x);
    ~Matrix();
 
    Matrix operator+(const Matrix& M);
    Matrix operator-(Matrix& M);
    Matrix& operator=(const Matrix&);
    Matrix operator*(Matrix& M);
 
    friend Matrix operator*(int x, Matrix& M);
    friend Matrix operator*(Matrix& M, int x);
 
};
Matrix.cpp

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
void Matrix::deleteMatrix()    //Удаляет текущую матрицу
{
    for (int i = 0; i < m_n; i++)
        delete[]m_mat[i];
    delete[]m_mat;
}
 
void Matrix::memoryAllocation(int n)   // Выделяет память для матрицы
{
    memoryAllocation(n, n);
}
 
void Matrix::memoryAllocation(int n, int m)  // С двумя параметрами
{
    if (n < 2 || m < 2)
        cout << "Кол-во строк и столбцов не может быть меньше : 2!!!" << endl;
    else
    {
        m_n = n;
        m_m = m;
        m_mat = new int* [m_n];
        for (int i = 0; i < m_n; i++)
            m_mat[i] = new int[m_m];
        for (int i = 0; i < m_n; i++)
            for (int j = 0; j < m_m; j++)
                m_mat[i][j] = 0;
    }
 
}
 
Matrix& Matrix::operator=(const Matrix& M)    // Равно
{
    cout << "=" << endl;
    if (M.m_n != m_n || M.m_m != m_m)
    {
        deleteMatrix();
        memoryAllocation(M.m_n, M.m_m);
    }
    for (int i = 0; i < m_n; i++)
        for (int j = 0; j < m_m; j++)
            m_mat[i][j] = M.m_mat[i][j];
    return *this;
}
 
Matrix Matrix::operator+(const Matrix& M)   // Плюс
{
    Matrix buffer(M.m_n, M.m_m);
 
    if (M.m_n == m_n && M.m_m == m_m)
    {
        buffer.deleteMatrix();
        buffer.memoryAllocation(m_n, m_m);
        for (int i = 0; i < m_n; i++)
            for (int j = 0; j < m_m; j++)
                buffer.m_mat[i][j] = m_mat[i][j] + M.m_mat[i][j];
    }
    else
        cout << "Кол-во столбцов и строк должно быть одинаковым!!!" << endl;
    return buffer;
}
 
Matrix Matrix::operator-(Matrix& M)    // Минус
{
    Matrix buffer(M.m_n, M.m_m);
    if (M.m_n == m_n && M.m_m == m_m)
    {
        for (int i = 0; i < m_n; i++)
            for (int j = 0; j < m_m; j++)
                m_mat[i][j] -= M.m_mat[i][j];
    }
    else
        cout << "Кол-во столбцов и строк должно быть одинаковым!!!" << endl;
    return buffer;
}
 
Matrix Matrix::operator*(Matrix& M)   // Умножение двух матриц
{
    Matrix buffer(m_n, M.m_m);  // перемножение двух разных по размеру матриц: n = первая матрица, m = вторая матрица
    
    for (int i = 0; i < buffer.m_n; i++)
        for (int j = 0; j < m_m; j++)
        {
            for (int index = 0; index < buffer.m_n; index++)
                buffer.m_mat[i][j] += m_mat[i][index] * M.m_mat[index][j];
        }
    return buffer;
}
 
Matrix operator*(int x, Matrix& M)   // Умножение числа на матрицу
{
    Matrix buffer(M.m_n, M.m_m);
    for (int i = 0; i < M.m_n; i++)
        for (int j = 0; j < M.m_m; j++)
            buffer = M.m_mat[i][j] * x;
    return buffer;
}
 
Matrix operator*(Matrix& M, int x)  // Умножение числа на матрицу
{
    Matrix buffer(M.m_n, M.m_m);
    for (int i = 0; i < M.m_n; i++)
        for (int j = 0; j < M.m_m; j++)
            buffer = M.m_mat[i][j] * x;
    return buffer;
}
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
05.11.2019, 20:09
Ответы с готовыми решениями:

Матрицы - перегрузка операторов >> и <<
Здравствуйте! Помогите, пожалуйста. Компилятор ругается на мою попытку перегрузить операторы ввода и вывода. Не знаю как исправить,...

Классы, матрицы, перегрузка операторов, дружественные функции
Гляньте пожалуйста, как получилось сделать задание, что неверно: Создать класс, в котором перегрузить операторы: &amp; для...

Перегрузка операторов для list
Как перегрузить операторы вывода в поток и доступа по индексу для list?

15
913 / 339 / 135
Регистрация: 18.07.2017
Сообщений: 1,485
06.11.2019, 11:21
В яндексе не пробовал искать?
https://metanit.com/cpp/tutorial/5.14.php
https://www.bestprog.net/ru/20... rs-ru/#q07
Или на форуме?
https://www.cyberforum.ru/sear... d=16280504
0
1 / 1 / 0
Регистрация: 03.01.2019
Сообщений: 11
06.11.2019, 17:13  [ТС]
Пробовал, но нигде не было примера с матрицами или что-то подобное
0
 Аватар для vlisp
1064 / 985 / 153
Регистрация: 10.08.2015
Сообщений: 5,368
06.11.2019, 17:20
Цитата Сообщение от l0lik Посмотреть сообщение
void Matrix::deleteMatrix() //Удаляет текущую матрицу
{
for (int i = 0; i < m_n; i++)
delete[]m_mat[i];
delete[]m_mat;
}
за такое надо бить по сусалам... для кого деструктор придумали?
0
1 / 1 / 0
Регистрация: 03.01.2019
Сообщений: 11
06.11.2019, 21:50  [ТС]
Но деструктор удаляет все поля или я чего-то не знаю?
0
 Аватар для vlisp
1064 / 985 / 153
Регистрация: 10.08.2015
Сообщений: 5,368
06.11.2019, 23:31
нельзя удалять содержимое матрицы вне деструктора. это ведет к ошибкам
то же самое касается memoryAllocation(int n, int m)
нельзя создавать контент вне конструктора. эти два метода должны делать противоположное - создавать и уничтожать.
Цитата Сообщение от l0lik Посмотреть сообщение
Matrix Matrix::operator-(Matrix& M) // Минус
{
Matrix buffer(M.m_n, M.m_m);
if (M.m_n == m_n && M.m_m == m_m)
{
for (int i = 0; i < m_n; i++)
for (int j = 0; j < m_m; j++)
m_mat[i][j] -= M.m_mat[i][j];
}
else
cout << "Кол-во столбцов и строк должно быть одинаковым!!!" << endl;
return buffer;
}
зачем ты здесь пишешь в консоль? это жизненно необходимо? что если на входе будут не квадратные матрицы? что вернет метод? и где будет использован этот результат??? за такое нужно бить по рукам линейкой
0
1 / 1 / 0
Регистрация: 03.01.2019
Сообщений: 11
07.11.2019, 17:50  [ТС]
Я сделал проверку для того, чтобы узнать одинаковый ли размер у матриц. Отнимать матрицы разных размеров нельзя. Согласен, метод ничего не вернет, если они разные.
Если нельзя создавать и удалять вне конструктора, как менять размер матрицы?
0
 Аватар для vlisp
1064 / 985 / 153
Регистрация: 10.08.2015
Сообщений: 5,368
07.11.2019, 18:05
Цитата Сообщение от l0lik Посмотреть сообщение
метод ничего не вернет,
с чего бы это??? он вернет матрицу заполненную нулями, в лучшем случае.
правильное поведение - кинуть исключение. знаешь как разбиваются самолеты? вот из-за таких ошибок
а что если тебе надо перемножить миллион таких матриц? каждый раз будешь проверять и писать в консоль?
0
1 / 1 / 0
Регистрация: 03.01.2019
Сообщений: 11
07.11.2019, 18:33  [ТС]
Это обычное задание, которое дают в колледже. Мне не нужно обрабатывать такой объем информации
0
913 / 339 / 135
Регистрация: 18.07.2017
Сообщений: 1,485
07.11.2019, 18:59
Цитата Сообщение от vlisp Посмотреть сообщение
нельзя удалять содержимое матрицы вне деструктора. это ведет к ошибкам
то же самое касается memoryAllocation(int n, int m)
нельзя создавать контент вне конструктора.

Не по теме:

Компилятор не запрещает, значит можно)

Если у вас размерность матрицы меняется динамически, то придется управлять памятью вручную.
Можно, конечно каждый раз создавать новую, инициализировать, а старую удалять, но времени и памяти это займет больше.
Цитата Сообщение от l0lik Посмотреть сообщение
Matrix(int n, int x);
А где этот конструктор?
Цитата Сообщение от l0lik Посмотреть сообщение
Согласен, метод ничего не вернет, если они разные.
Ничего не возвращает void. А в вашем случае buffer возвращается в независимости от того, выполнилось условие или нет.
Цитата Сообщение от l0lik Посмотреть сообщение
Если нельзя создавать и удалять вне конструктора, как менять размер матрицы?
Как я писал сверху, можно. Только это внесет много гемора в вашу работу.
1
1 / 1 / 0
Регистрация: 03.01.2019
Сообщений: 11
07.11.2019, 19:25  [ТС]
Вот все конструкторы и деструктор
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Matrix::Matrix()
{
    m_n = 2;
    m_m = 2;
    memoryAllocation(m_n, m_m);
    cout << "Matrix(): " << this << endl;
}
 
Matrix::Matrix(int n, int m, int x)
{
    memoryAllocation(n, m);
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            m_mat[i][j] = x;
}
 
Matrix::Matrix(int n, int x = 0)
{
    memoryAllocation(n);
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            m_mat[i][j] = x;
}
 
Matrix::~Matrix()
{
    for (int i = 0; i < m_n; i++)
        delete[]m_mat[i];
    delete[]m_mat;
    cout << "~Matrix(): " << this << endl;
}
Добавлено через 4 минуты
Дело в том, что перегрузка = работает (в конструкторе и деструкторе есть вывод, который указывает на их вызов)
Но если вызвать +, -, * все летит к чертям.
До этого я возвращал ссылку из методов, как я понял, это было не правильно, так как все переменные удаляются после завершения функции. Попробовал вернуть объект - та же проблема...
0
913 / 339 / 135
Регистрация: 18.07.2017
Сообщений: 1,485
07.11.2019, 21:56
Операторы не работают из-за двойного выделения памяти.
Давайте рассмотрим что происходит у вас в коде...
C++
1
2
3
4
5
6
Matrix Matrix::operator-(Matrix& M)    // Минус
{
    Matrix buffer(M.m_n, M.m_m);
    ...
    return buffer;
}
1) В операторе- создается матрица buffer
2) Выполняются все необходимые операции над ней.
3) Вызывается конструктор копирования (который у вас не определен) для возвращаемого значения. Из-за чего на стеке оказывается неправильная копия матрицы buffer
4) Вызывается деструктор для buffer
5) Выход из функции
6) Вызов деструктора для копии, которая передана через стек.

Лечится созданием конструктора копирования

Matrix.cpp
C++
1
2
3
4
5
6
Matrix::Matrix(const Matrix& M){
    memoryAllocation(M.m_n, M.m_m);
        for (int i = 0; i < m_n; i++)
            for (int j = 0; j < m_m; j++)
                m_mat[i][j] = M.m_mat[i][j];
}
Matrix.h
C++
1
2
3
4
5
6
class Matrix
{
    ...
    Matrix(const Matrix& M);
    ...
}
Правило большой тройки. На эту тему писали на хабре.
https://habr.com/ru/post/61132/
https://habr.com/ru/post/31346/

Добавлено через 45 секунд
Цитата Сообщение от assemberist Посмотреть сообщение
У вас баг. В конструкторе Matrix::Matrix(int n, int x = 0) создается квадратная матрица, инициализированная числом x. А в перегруженных операторах, как я понял, нужно создавать именно матрицу размером n*m. Из-за этого при попытке присвоить результат вылезет ошибка аллокации.
Верно только для оператора-. В остальных память освобождается и выделяется заново.
А вцелом операторы не работают из-за двойного выделения памяти.
Давайте рассмотрим что происходит у вас в коде...
C++
1
2
3
4
5
6
Matrix Matrix::operator-(Matrix& M)    // Минус
{
    Matrix buffer(M.m_n, M.m_m);
    ...
    return buffer;
}
1) В операторе- создается матрица buffer
2) Выполняются все необходимые операции над ней.
3) Вызывается конструктор копирования (который у вас не определен) для возвращаемого значения. Из-за чего на стеке оказывается неправильная копия матрицы buffer
4) Вызывается деструктор для buffer
5) Выход из функции
6) Вызов деструктора для копии, которая передана через стек.

Лечится созданием конструктора копирования

Matrix.cpp
C++
1
2
3
4
5
6
Matrix::Matrix(const Matrix& M){
    memoryAllocation(M.m_n, M.m_m);
        for (int i = 0; i < m_n; i++)
            for (int j = 0; j < m_m; j++)
                m_mat[i][j] = M.m_mat[i][j];
}
Matrix.h
C++
1
2
3
4
5
6
class Matrix
{
    ...
    Matrix(const Matrix& M);
    ...
}
Правило большой тройки. На эту тему писали на хабре.
https://habr.com/ru/post/61132/
https://habr.com/ru/post/31346/
1
1 / 1 / 0
Регистрация: 03.01.2019
Сообщений: 11
07.11.2019, 21:56  [ТС]
main.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <Windows.h>
#include "Matrix.h"
 
int main()
{
    SetConsoleOutputCP(1251);
    Matrix a(3, 3, 5);  //Создается матрица 3 на 3 и заполняется 5
    Matrix b(3, 3, 2);  //Создается матрица 3 на 3 и заполняется 2
    Matrix c(3, 3, 1);  //Создается матрица 3 на 3 и заполняется 1
 
    //a.randomMatrix();
    
    std::cout << "Matrix a:" << std::endl;  // Вывод матрицы а
    a.printMatrix();                        // 
 
    std::cout << "Matrix b:" << std::endl;  // Вывод матрицы b
    b.printMatrix();                        //
 
    c = a * b;
 
    std::cout << "Matrix c:" << std::endl;  // Вывод матрицы c
    c.printMatrix();                        //
 
    return 0;
}
Для наглядности, я добавил в конструкторы строку, которая выводит ссылку создающегося объекта

Консоль:
Matrix(): 010FF830
Matrix(): 010FF81C
Matrix(): 010FF808
Matrix a:
5 5 5
5 5 5
5 5 5
Matrix b:
2 2 2
2 2 2
2 2 2
Matrix(): 010FF6DC
~Matrix(): 010FF6DC
=

A:\путь (процесс 13760) завершает работу с кодом -1073741819...

Знак "=" указывает на вызов перегрузки.
0
913 / 339 / 135
Регистрация: 18.07.2017
Сообщений: 1,485
07.11.2019, 22:03
Лучший ответ Сообщение было отмечено l0lik как решение

Решение

А вцелом операторы не работают из-за двойного выделения памяти.
Давайте рассмотрим что происходит у вас в коде...
C++
1
2
3
4
5
6
Matrix Matrix::operator-(Matrix& M)    // Минус
{
    Matrix buffer(M.m_n, M.m_m);
    ...
    return buffer;
}
1) В операторе- создается матрица buffer
2) Выполняются все необходимые операции над ней.
3) Вызывается конструктор копирования (который у вас не определен) для возвращаемого значения. Из-за чего на стеке оказывается неправильная копия матрицы buffer
4) Вызывается деструктор для buffer
5) Выход из функции
6) Вызов деструктора для копии, которая передана через стек.

Лечится созданием конструктора копирования

Matrix.cpp
C++
1
2
3
4
5
6
Matrix::Matrix(const Matrix& M){
    memoryAllocation(M.m_n, M.m_m);
        for (int i = 0; i < m_n; i++)
            for (int j = 0; j < m_m; j++)
                m_mat[i][j] = M.m_mat[i][j];
}
Matrix.h
C++
1
2
3
4
5
6
class Matrix
{
    ...
    Matrix(const Matrix& M);
    ...
}
Правило большой тройки. На эту тему писали на хабре.
https://habr.com/ru/post/61132/
https://habr.com/ru/post/31346/
1
1 / 1 / 0
Регистрация: 03.01.2019
Сообщений: 11
07.11.2019, 22:18  [ТС]
Спасибо, все заработало, программа не ломается.
Вопрос, конструктор копирования вызывается неявно перед концом метода?

Добавлено через 11 минут
assemberist помог в решении проблемы, тема закрыта
1
913 / 339 / 135
Регистрация: 18.07.2017
Сообщений: 1,485
07.11.2019, 22:21
Он вызывается всегда когда новый объект строится на основе другого.
Например так
C++
1
2
3
4
int main(){
        Matrix m();
        Matrix n(m);
}
В вашем случае неявно
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
07.11.2019, 22:21
Помогаю со студенческими работами здесь

Перегрузка операторов для контейнера
Доброго времени суток. Просматривая STL, в ветке вектора наткнулся на такую интересную запись: vector&lt;int&gt; v1 = {45,85,68}; ...

Перегрузка операторов не для объектов
Можно ли так делать? Потому что в таком случае вызывается не мой оператор, а исключающее или, стандарнтое. Как и что сделать, чтобы...

Перегрузка операторов для списков
Как сделать перегрузку оператора умножить (оператор возвращает адрес первого элемента списка нового списка, который содержит общие элементы...

Перегрузка операторов для класса
class A { private: size_t i; public: size_t i_get() { return i; } };

Перегрузка операторов для классов
Определить класс описывающий вектор в пространстве. Для класса перегрузить префиксный унарный оператор. Написать программу в которой...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Новые блоги и статьи
Символьное дифференцирование
igorrr37 13.02.2026
/ * Программа принимает математическое выражение в виде строки и выдаёт его производную в виде строки и вычисляет значение производной при заданном х Логарифм записывается как: (x-2)log(x^2+2) -. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru