Форум программистов, компьютерный форум CyberForum.ru

Класс Матрица - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 23, средняя оценка - 4.74
miriganua
129 / 100 / 4
Регистрация: 05.02.2012
Сообщений: 241
05.02.2012, 00:24     Класс Матрица #1
Вообщем задали мне в универе написать программу для работы с матрицами. Для этого нужно создать класс Матрица. Вообщем я только начал и сделал некоторые наброски(конструкторы и деструкторы)ю
Вообщем кому не трудно проверьте.

Заголовочный файл classMatrix.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
#ifndef classMatrix_h
#define classMatrix_h
 
#include <iostream>
 
using namespace std;
 
class Matrix
{
    //classes for exception handling
    class IncorrectSize { }; 
private:
    double** a;
    int row, col;
public:
    //constructor of a matrix with certain sizes
    Matrix(int amount_of_row, int amount_of_col);
    //copy constructor
    Matrix(const Matrix& m);
 
    //destructor
    ~Matrix();
};
 
#endif
Файл classMatrix.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
#include <iostream>
#include "classMatrix.h"
 
using namespace std;
 
Matrix::Matrix(int amount_of_row, int amount_of_col)
{
    if (amount_of_row < 2 || amount_of_col < 2)
    {
        throw IncorrectSize(); 
    }
    row = amount_of_row;
    col = amount_of_col;
    a = new double* [row];
    for (int i = 0; i < row; i++)
    {
        a[i] = new double [col]; 
    }
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            a[i][j] = 0;
        }
    }
}
 
Matrix::Matrix(const Matrix& m)
{
    row = m.row;
    col = m.col;
    a = new double* [row];
    for (int i = 0; i < row; i++)
    {
        a[i] = new double [col]; 
    }
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            a[i][j] = m.a[i][j];
        }
    }
}
 
Matrix::~Matrix()
{
    for (int i = 0; i < row; i++)
    {
        delete [] a[i];
    }
    delete [] a;
}
Файл тестирование класса Teting of the class:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include "classMatrix.h"
 
using namespace std;
 
int main()
{
    try
    {
        Matrix A(3, 3);
    }
    catch (Matrix::IncorrectSize)
    {
        cout << "Matrix with such sizes can not exist." << '\n';
    }
    return 0;
}
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
05.02.2012, 00:24     Класс Матрица
Посмотрите здесь:

C++ Класс Матрица
с++ класс матрица C++
Класс матрица C++
Класс матрица C++
C++ Класс матрица
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
dr.curse
 Аватар для dr.curse
386 / 342 / 16
Регистрация: 11.10.2010
Сообщений: 1,907
05.02.2012, 00:33     Класс Матрица #2
Игорь Миронюк, а что именно проверить? В коде вроде бы все нормально.
miriganua
129 / 100 / 4
Регистрация: 05.02.2012
Сообщений: 241
05.02.2012, 01:03  [ТС]     Класс Матрица #3
Ну, я имею в виду обработку исключений в конструкторе, деструктор, подключение библиотек и пространство имен, стражей и т.п.
I.M.
 Аватар для I.M.
564 / 547 / 5
Регистрация: 16.12.2011
Сообщений: 1,389
05.02.2012, 03:42     Класс Матрица #4
Вроде бы все хорошо.
Только я стандартные заголовочные файлы вынес бы в отдельный файл и подключал уже его.
Затем, ограничение на мин. размерность матрицы. Наверное, стоило бы сделать переменные row и col беззнаковыми. И тогда исключение IncorrectSize можно кидать только если row или col равны нулю.
Сейчас вы почему-то не даете создать матрицу 1х1, хотя по факту число тоже можно назвать матрицей)
Также я бы добавил пустой конструктор (создающий пустую матрицу 0х0 или, например, матрицу 1х1).
Ну и жесткая привязка к типу double. Хотя может так и надо, я не знаю всего вашего задания. Если от вас хотят получить контейнер "матрица", то к double не следует привязываться.
miriganua
129 / 100 / 4
Регистрация: 05.02.2012
Сообщений: 241
05.02.2012, 14:26  [ТС]     Класс Матрица #5
По вашему совету ,I.M., сделал конструктор пустой матицы(0х0). Можете объяснить зачем он нужен. row и col оставил без изменений, посчитал что так будет лучше(вдруг кого-нибудь пробьет попробовать создать матрицу с отрицательными размерами). Стандартные заголовочные файлы вынес в отдельный файл. double по условию задания. Спасибо.

Файл standardHeaderFiles.h:

C++
1
2
3
4
5
6
7
8
#ifndef standardHeaderFiles_h
#define standardHeaderFiles_h
 
#include <iostream>
 
using namespace std;
 
#endif
Заголовочный файл classMatrix.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
#ifndef classMatrix_h
#define classMatrix_h
 
#include "standardHeaderFiles.h"
 
class Matrix
{
    //classes for exception handling
    class IncorrectSize { }; 
private:
    double** a;
    int row, col;
public:
    //constructor of a matrix with certain sizes
    Matrix(int amount_of_row, int amount_of_col);
    //copy constructor
    Matrix(const Matrix& mat);
    //empty matrix
    Matrix();
 
    //destructor
    ~Matrix();
};
 
#endif
Файл classMatrix.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
#include "standardHeaderFiles.h"
#include "classMatrix.h"
 
Matrix::Matrix(int amount_of_row, int amount_of_col)
{
    if (amount_of_row < 1 || amount_of_col < 1)
    {
        throw IncorrectSize(); 
    }
    row = amount_of_row;
    col = amount_of_col;
    a = new double* [row];
    for (int i = 0; i < row; i++)
    {
        a[i] = new double [col]; 
    }
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            a[i][j] = 0;
        }
    }
}
 
Matrix::Matrix(const Matrix& mat)
{
    row = mat.row;
    col = mat.col;
    a = new double* [row];
    for (int i = 0; i < row; i++)
    {
        a[i] = new double [col]; 
    }
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            a[i][j] = mat.a[i][j];
        }
    }
}
 
Matrix::Matrix()
{
    row = 0;
    col = 0;
    a = 0;
}
 
Matrix::~Matrix()
{
    for (int i = 0; i < row; i++)
    {
        delete [] a[i];
    }
    delete [] a;
}
Файл тестирование класса Teting of the class:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "standardHeaderFiles.h"
#include "classMatrix.h"
 
int main()
{
    try
    {
        Matrix A(3, 3);
        Matrix B(A);
        Matrix C();
    }
    catch (Matrix::IncorrectSize)
    {
        cout << "Matrix with such sizes can not exist." << '\n';
    }
    return 0;
}
retmas
Жарю без масла
803 / 685 / 143
Регистрация: 13.01.2012
Сообщений: 1,580
05.02.2012, 14:52     Класс Матрица #6
если ваш конструктор по умолчанию создает матрицу 0х0, то было бы логично и другим конструкторам позволить это.
например,
C++
1
2
3
4
Matrix m1; // 0x0
// пусть в классе матрицы определены методы,
// возвращающие кол-во строк и столбцов. тогда
Matrix m2(m1.rows(), m1.cols()); // выбросит исключение. нелогично
если вы хотите обеспечить неотрицательные размерности, используйте size_t
C++
1
Matrix(size_t amount_of_row, size_t amount_of_col);
теперь размерности всегда неотрицательны. а если кто-то напишет
C++
1
Matrix m1(-1, -3);
компилятор выдаст предупреждение

Добавлено через 3 минуты
по мне standardHeaderFiles.h - лишнее, а писать в заголовках
C++
1
using namespace std;
не есть гуд
I.M.
 Аватар для I.M.
564 / 547 / 5
Регистрация: 16.12.2011
Сообщений: 1,389
05.02.2012, 17:52     Класс Матрица #7
Я потому и упомянул о беззнаковых типах, чтобы избежать отрицательных значений.
О пустом конструкторе я написал по аналогии со стандартными контейнерами. Там же не обязательно сразу же задавать размеры будущего массива. Можно создать просто пустой массив. А для этого никакие параметры не нужны.
Другой вопрос - что считать пустой матрицей. Логично было бы 0х0. Но если вам так не хочется видеть нули в размерах, то можно сделать 1х1.
Про пространства имен в общем заголовке действительно лучше не писать. По поводу необходимости такого заголовочного файла - решайте сами. Я обычно использую подобный файл, поэтому и посоветовал.
miriganua
129 / 100 / 4
Регистрация: 05.02.2012
Сообщений: 241
05.02.2012, 23:57  [ТС]     Класс Матрица #8
Нестыковку с конструкторами вроде решил. Отрицательные значения отбрасывать не хочу, потому что в будущем вижу такую ситуацию: пользователь вводит отрицательный размер, а программа ему пишет об ошибке. Проблемку с заголовочными файлами и пространством имен не решил, посему прошу подсказать, а то чето совсем запутался.

Дополнил класс действиями +,-,* для матриц; вводом и выводом матрицы; сделал оператор присвоения. Вот что получилось:

Заголовочный файл classMatrix.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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#ifndef classMatrix_h
#define classMatrix_h
 
#include <iostream>
 
using namespace std;
 
class Matrix
{
    //classes for exception handling
    class IncorrectSize { }; 
    class IrrelevantSizes { };
 
    //input the matrix
    friend istream& operator>>(istream& in, Matrix& mat);
    //output the  matrix
    friend ostream& operator<<(ostream& out, const Matrix& mat);
 
    //addition operator
    friend Matrix operator+(const Matrix& mat1, const Matrix& mat2);
    //subtraction operator
    friend Matrix operator-(const Matrix& mat1, const Matrix& mat2);
    //multiplication operator
    friend Matrix operator*(const Matrix& mat1, const Matrix& mat2);
private:
    double** a;
    int row, col;
 
public:
    //constructor of a matrix with certain sizes
    Matrix(int amount_of_row, int amount_of_col);
    //copy constructor
    Matrix(const Matrix& mat);
    //empty matrix
    Matrix();
 
    //destructor
    ~Matrix();
 
    //assignment
    void operator=(const Matrix& mat);
};
 
#endif
Файл classMatrix.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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include "classMatrix.h"         
                                 
Matrix::Matrix(int amount_of_row, int amount_of_col)
{
    if (amount_of_row < 0 || amount_of_col < 0)
    {
        throw IncorrectSize(); 
    }
    row = amount_of_row;
    col = amount_of_col;
    a = new double* [row];
    for (int i = 0; i < row; i++)
    {
        a[i] = new double [col]; 
    }
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            a[i][j] = 0;
        }
    }
}
 
Matrix::Matrix(const Matrix& mat)
{
    row = mat.row;
    col = mat.col;
    a = new double* [row];
    for (int i = 0; i < row; i++)
    {
        a[i] = new double [col]; 
    }
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            a[i][j] = mat.a[i][j];
        }
    }
}
 
Matrix::Matrix()
{
    row = 0;
    col = 0;
    a = 0;
}
 
Matrix::~Matrix()
{
    for (int i = 0; i < row; i++)
    {
        delete [] a[i];
    }
    delete [] a;
}
 
void Matrix::operator=(const Matrix& mat)
{
    if (row != mat.row || col != mat.col)
    {
        throw IrrelevantSizes();
    }
    for (int i = 0; i < mat.row; i++)
    {
        for (int j = 0; j < mat.col; j++)
        {
            a[i][j] = mat.a[i][j];
        }
    }
}
 
istream& operator>>(istream& in, Matrix& mat)
{
    for (int i = 0; i < mat.row; i++)
    {
        for (int j = 0; j < mat.col; j++)
        {
            in >> mat.a[i][j];
        }
    }
      
    return in;
}
 
ostream& operator<<(ostream& out, const Matrix& mat)
{
    for (int i = 0; i < mat.row; i++)
    {
        for (int j = 0; j < mat.col; j++)
        {
            out << mat.a[i][j] << "   ";
        }
        out << '\n';
    }
    return out;
}
 
Matrix operator+(const Matrix& mat1, const Matrix& mat2)
{
    if (mat1.row != mat2.row || mat1.col != mat2.col)
    {
        throw Matrix::IrrelevantSizes();
    }
    Matrix mat(mat1.row, mat1.col);
    for (int i = 0; i < mat.row; i++)
    {
        for (int j = 0; j < mat.col; j++)
        {
            mat.a[i][j] = mat1.a[i][j] + mat2.a[i][j];
        }
    }
    return mat;
}
 
Matrix operator-(const Matrix& mat1, const Matrix& mat2)
{
    if (mat1.row != mat2.row || mat1.col != mat2.col)
    {
        throw Matrix::IrrelevantSizes();
    }
    Matrix mat(mat1.row, mat1.col);
    for (int i = 0; i < mat.row; i++)
    {
        for (int j = 0; j < mat.col; j++)
        {
            mat.a[i][j] = mat1.a[i][j] - mat2.a[i][j];
        }
    }
    return mat;
}
 
Matrix operator*(const Matrix& mat1, const Matrix& mat2)
{
    if (mat1.col != mat2.row)
    {
        throw Matrix::IrrelevantSizes();
    }
    Matrix mat(mat1.row, mat2.col);
    for (int i = 0; i < mat.row; i++)
    {
        for (int j = 0; j < mat.col; j++)
        {
            for (int k = 0; k < mat1.col; k++)
            {
                mat.a[i][j] += mat1.a[i][k] * mat2.a[k][j];
            }
        }
    }
    return mat;
}
Файл тестирование класса Teting of the class:

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 "classMatrix.h"
#include <iostream>
 
using namespace std;
 
int main()
{
    try
    {
        Matrix A(3, 3);
        Matrix B(3, 3);
        cin >> A >> B;
        cout << A * B << '\n';
        cout << A + B << '\n';
        cout << A - B << '\n';
    }
    catch (Matrix::IncorrectSize)
    {
        cout << "Matrix with such sizes can not exist." << '\n';
    }
    catch (Matrix::IrrelevantSizes)
    {
        cout << "Matrices have irrelevant sizes." << '\n';
    }
    return 0;
}
retmas
Жарю без масла
803 / 685 / 143
Регистрация: 13.01.2012
Сообщений: 1,580
06.02.2012, 00:16     Класс Матрица #9
Цитата Сообщение от Игорь Миронюк Посмотреть сообщение
пользователь вводит отрицательный размер, а программа ему пишет об ошибке.
стоит ли делать для этого исключения в классе? ну хорошо. пусть так...
тогда пользователь может пытаться вводить неверные данные(буквы, например) в матрицу. чем этот случай хуже? тоже исключения? можно. нужно ли?
вобщем, если уж вы хотите обрабатывать подобные ошибки, и делать это с помощью исключений, делайте это везде.
и надеюсь, когда ваш класс станет более завершенным, вы избавитесь от френдов
miriganua
129 / 100 / 4
Регистрация: 05.02.2012
Сообщений: 241
06.02.2012, 00:52  [ТС]     Класс Матрица #10
А разве "друзья" это плохо. Просто, на мой взгляд, логично эти действия сделать не в качестве метода класса или может сделать это статическими функциями(а для них перегрузка возможна?). А насчет обработки исключений в конструкторе вы правы, а в случае умножения и т.п. А как насчет инклудов(я не уверен в правильности)?
I.M.
 Аватар для I.M.
564 / 547 / 5
Регистрация: 16.12.2011
Сообщений: 1,389
06.02.2012, 02:41     Класс Матрица #11
Зачем вам френды для сложения, вычитания и умножения? Аналогичный вопрос был бы, объяви вы их не френдами, а статическими. И без этих спецификаторов все будет работать.
По поводу ненужности френдов для перегрузки ввода/вывода в поток не уверен. Лично я, имея не очень большой опыт, видел только такой способ перегрузки << и >>. Поэтому тут я френды бы оставил.
Немного не осознал исключение в operator=. В стандартных контейнерах в таком случае происходит обычное копирование с выделением/освобождением памяти, если нужно.
retmas
Жарю без масла
803 / 685 / 143
Регистрация: 13.01.2012
Сообщений: 1,580
06.02.2012, 17:18     Класс Матрица #12
Цитата Сообщение от Игорь Миронюк Посмотреть сообщение
логично эти действия сделать не в качестве метода класса
вполне логично. вот и сделайте их всех свободными ф-ми и без всяких френдов.

Цитата Сообщение от Игорь Миронюк Посмотреть сообщение
А разве "друзья" это плохо.
друзья - это довольно редкая необходимость(и то наверняка найдется способ обойтись без них, если это оправдано), которой в вашем классе (я почему-то уверен) не будет:
наверняка у вас будут методы доступа к элементам матрицы
C++
1
2
3
4
5
6
// в таком виде
m[i][j];
// а может в таком виде
m.element(i,j);
// а может как-то иначе
// ...
как вы записываете матрицу в поток или считываете? по сути используя
C++
1
m.a[i][j]
но зачем вам знать о внутреннем представлении матрицы m и, конкретно, что в представлении класса есть некий указатель на массив а, если можно будет использовать открытые методы доступа к элементам матрицы и использовать их для операций io.
Felsurt
5 / 5 / 0
Регистрация: 06.02.2012
Сообщений: 19
06.02.2012, 17:52     Класс Матрица #13
замечания, которые сразу бросаются в глаза

1. Очень плохо использовать using дерективы в заголовочных файлах (в вашем случае 6: using namespace std.
Краткое пояснение.
Я пользуюсь своей функцией sort, она мне очень нравиться, но другие алгоритмы использую из <algorithm>
для них я явно прописываю std::name ну или прописал необходимые using объявления. Иными словами моя функция sort никак не пересекается со стандартной.
Но стоит мне подключить заголовочник с вашей матрицей, как на весь мой код начнет действовать using деректива всего пространства std и я тут же получу множество конфликтов своей функции sort со стандартной.
Я надеюсь, что этот пример пояснил немного, почему это не здорово

2. Конструктор не должен (!) выбрасывать исключений. Это грубейшая ошибка, которая приводит к утечкам памяти.
Дело в том, что выбросив исключение из конструктора вы больше не можете гарантировать в каком состоянии находиться объект.

3. В конструкторе по умолчанию вы не выделяете память и зануляете указатель, но в деструкторе обращаетесь к i-тому элементу, чтобы очистить строку.
Думаю проблема очевидна

Ну и на последок: хорошим тоном проектирования класса является следующее:
Весь базовый функционал (необходимый минимум) сделать методами класса, все остальное внешними функциями.
Например: если вы поместили нечто в метод класса, то фактически вы обязываете меня пользоваться этим методом, но если вы сделали это нечто отдельным методом, то вы даете мне возможность заменить это своей реализацией.
Зачем это нужно: вы можете гарантировать, что ваша реализация самая лучшая во всем мире и что она устроит по точности/скорости всех пользователей вашего класса?

И еще, не проще ли было хранить матрицу в виде одномерного массива?
retmas
Жарю без масла
803 / 685 / 143
Регистрация: 13.01.2012
Сообщений: 1,580
06.02.2012, 18:11     Класс Матрица #14
Цитата Сообщение от Felsurt Посмотреть сообщение
Конструктор не должен (!) выбрасывать исключений.
бред. с чего вы взяли?
Цитата Сообщение от Felsurt Посмотреть сообщение
Это грубейшая ошибка, которая приводит к утечкам памяти
нет там такого. память не выделяется до возможной генерации исключения.
Цитата Сообщение от Felsurt Посмотреть сообщение
Дело в том, что выбросив исключение из конструктора вы больше не можете гарантировать в каком состоянии находиться объект.
этого и не нужно: после раскрутки стека - обьекта нет. о каком состоянии объекта идет речь?

Добавлено через 4 минуты
к тому же в конструкторах объектов зачастую выделяется память с помощью оператора new, в результате чего может быть сгенерировано исключение bad_alloc. т.е. по вашему все такие конструкторы - потенциальные бомбы и недопустимы
Felsurt
5 / 5 / 0
Регистрация: 06.02.2012
Сообщений: 19
06.02.2012, 18:12     Класс Матрица #15
Цитата Сообщение от retmas Посмотреть сообщение
нет там такого. память не выделяется до возможной генерации исключения.
а, то есть на внутренние поля память не нужна

Цитата Сообщение от retmas Посмотреть сообщение
этого и не нужно: после раскрутки стека - обьекта нет. о каком состоянии объекта идет речь?
C++
1
2
3
4
5
6
7
8
Matrix *ob;
try {
    ob = new Matrix(1,1);
} catch (...) {
   // что с объектом?
   // я был в конструкторе! я работал с внутренними полями! значит память под них выделена!
   // но где она?
}
не знаю как у остальных. но меня кирилица не читабель в теге Cpp, поэтому скопирую текст из блока catch:
// что с объектом?
// я был в конструкторе! я работал с внутренними полями! значит память под них выделена!
// но где она?
retmas
Жарю без масла
803 / 685 / 143
Регистрация: 13.01.2012
Сообщений: 1,580
06.02.2012, 18:21     Класс Матрица #16
Цитата Сообщение от Felsurt Посмотреть сообщение
что с объектом?
нет его и не было при генерации исключения.

Цитата Сообщение от Felsurt Посмотреть сообщение
я работал с внутренними полями! значит память под них выделена!
ни с чем вы не работали и уж тем более никакой памяти на этапе исполнения не выделялось.
Felsurt
5 / 5 / 0
Регистрация: 06.02.2012
Сообщений: 19
06.02.2012, 18:26     Класс Матрица #17
Цитата Сообщение от retmas Посмотреть сообщение
нет его и не было при генерации исключения.

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

в вашем мире C++ гораздо легче и проще, чем в моем...
retmas
06.02.2012, 18:28
  #18

Не по теме:

Цитата Сообщение от Felsurt Посмотреть сообщение
в вашем мире C++ гораздо легче и проще, чем в моем...
да уж... не рвусь в ваш мир...

miriganua
129 / 100 / 4
Регистрация: 05.02.2012
Сообщений: 241
07.02.2012, 03:51  [ТС]     Класс Матрица #19
retmas, от друзей избавился, но делать отдельные функции делать не стал, действия с матрицами сделал методами, надеюсь это терпимо.


Felsurt, попытался учесть замечания
1. Думаю что исправил проблему с директивой using(но не уверен)
2. От исключения в конструкторе избавился, от него у меня много проблем
3. Здесь я думаю вы не учли, что у меня цикл и если row = 0, то в цикл мы не входим
4. А на счет методов - черт с ними!!!

Можете посоветовать наилучший способ нахождения определителя матрицы. Я почитал в инете, самый быстрый способ методом Гаусса: вначале привести к треугольному виду и тогда определитель равен произведению диагональных элементов; или лучше раскладывать по какой-то строке? А еще думаю сделать конструктор матрицы, полученной из данной вычеркиванием определенной строки и столбца. Такой конструктор, я думаю понадобится для нахожденияминора и алгебраического дополнения, да и в нахождении определителя может понадобится.

Вот дополненный класс:

Заголовочный файл classMatrix.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
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
#ifndef classMatrix_h
#define classMatrix_h
 
#include <iostream>
 
using std::istream;
using std::ostream;
 
class Matrix
{
    //classes for exception handling
    class IrrelevantSizes { };
    class NonexistentElement { };
 
    //input the matrix
    friend istream& operator>>(istream& in, Matrix& mat);
    //output the  matrix
    friend ostream& operator<<(ostream& out, const Matrix& mat);
private:
    double** a;
    int row, col;
public:
    //constructor of a matrix with certain sizes
    Matrix(int amount_of_row, int amount_of_col);
    //copy constructor
    Matrix(const Matrix& mat);
    //empty matrix
    Matrix();
 
    //destructor
    ~Matrix();
 
    //get sizes of the matrix
    int getAmountOfRows() const;
    int getAmountOfColumns() const;
 
    //get element
    double& element(int row_i, int col_j);
 
    //assignment
    void operator=(const Matrix& mat);
 
    //equals operator
    bool operator==(const Matrix& mat) const;
    //not equal operator
    bool operator!=(const Matrix& mat) const;
 
    //addition operator
    Matrix operator+(const Matrix& mat) const;
    //subtraction operator
    Matrix operator-(const Matrix& mat) const;
    //multiplication operator
    Matrix operator*(const Matrix& mat) const;
    Matrix operator*(double num) const;
};
 
#endif
Файл classMatrix.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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#include "classMatrix.h"         
                                 
Matrix::Matrix(int amount_of_row, int amount_of_col)
{
    row = amount_of_row;
    col = amount_of_col;
    a = new double* [row];
    for (int i = 0; i < row; i++)
    {
        a[i] = new double [col]; 
    }
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            a[i][j] = 0;
        }
    }
}
 
Matrix::Matrix(const Matrix& mat)
{
    row = mat.row;
    col = mat.col;
    a = new double* [row];
    for (int i = 0; i < row; i++)
    {
        a[i] = new double [col]; 
    }
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            a[i][j] = mat.a[i][j];
        }
    }
}
 
Matrix::Matrix()
{
    row = 0;
    col = 0;
    a = 0;
}
 
 
Matrix::~Matrix()
{
    for (int i = 0; i < row; i++)
    {
        delete [] a[i];
    }
    delete [] a;
}
 
 
int Matrix::getAmountOfRows() const
{
    return row;
}
 
int Matrix::getAmountOfColumns() const
{
    return col;
}
 
 
double& Matrix::element(int row_i, int col_j)
{
    if (row_i >= row || col_j >= col)
    {
        throw NonexistentElement();
    }
    return a[row_i][col_j];
}
 
 
void Matrix::operator=(const Matrix& mat)
{
    if(a)
    {
        for (int i = 0; i < row; i++)
        {
            delete [] a[i];
        }
        delete [] a;
    }
    row = mat.row;
    col = mat.col;
    a = new double* [row];
    for (int i = 0; i < row; i++)
    {
        a[i] = new double [col];
    }
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            a[i][j] = mat.a[i][j];
        }
    }
}
 
 
istream& operator>>(istream& in, Matrix& mat)
{
    for (int i = 0; i < mat.row; i++)
    {
        for (int j = 0; j < mat.col; j++)
        {
            in >> mat.a[i][j];
        }
    } 
    return in;
}
 
ostream& operator<<(ostream& out, const Matrix& mat)
{
    for (int i = 0; i < mat.row; i++)
    {
        for (int j = 0; j < mat.col; j++)
        {
            out << mat.a[i][j] << "   ";
        }
        out << '\n';
    }
    return out;
}
 
 
bool Matrix::operator==(const Matrix& mat) const
{
    if (row != mat.row || col != mat.col)
    {
        return false;
    }
    else
    {
        for (int i = 0; i < row; i++)
        {
            for (int j = 0; j < col; j++)
            {
                if(a[i][j] != mat.a[i][j])
                {
                    return false;
                }
            }
        }
        return true;
    }
}
 
bool Matrix::operator!=(const Matrix& mat) const
{
    if (row != mat.row || col != mat.col)
    {
        return true;
    }
    else
    {
        for (int i = 0; i < row; i++)
        {
            for (int j = 0; j < col; j++)
            {
                if(a[i][j] != mat.a[i][j])
                {
                    return true;
                }
            }
        }
        return false;
    }
}
 
 
Matrix Matrix::operator+(const Matrix& mat) const
{
    if (row != mat.row || col != mat.col)
    {
        throw Matrix::IrrelevantSizes();
    }
    Matrix new_mat(row, col);
    for (int i = 0; i < new_mat.row; i++)
    {
        for (int j = 0; j < new_mat.col; j++)
        {
            new_mat.a[i][j] = a[i][j] + mat.a[i][j];
        }
    }
    return new_mat;
}
 
Matrix Matrix::operator-(const Matrix& mat) const
{
    if (row != mat.row || col != mat.col)
    {
        throw Matrix::IrrelevantSizes();
    }
    Matrix new_mat(row, col);
    for (int i = 0; i < new_mat.row; i++)
    {
        for (int j = 0; j < new_mat.col; j++)
        {
            new_mat.a[i][j] = a[i][j] - mat.a[i][j];
        }
    }
    return new_mat;
}
 
Matrix Matrix::operator*(const Matrix& mat) const
{
    if (col != mat.row)
    {
        throw Matrix::IrrelevantSizes();
    }
    Matrix new_mat(row, mat.col);
    for (int i = 0; i < new_mat.row; i++)
    {
        for (int j = 0; j < new_mat.col; j++)
        {
            for (int k = 0; k < col; k++)
            {
                new_mat.a[i][j] += a[i][k] * mat.a[k][j];
            }
        }
    }
    return new_mat;
}
 
Matrix Matrix::operator*(double num) const
{
    Matrix new_mat(row, col);
    for (int i = 0; i < new_mat.row; i++)
    {
        for (int j = 0; j < new_mat.col; j++)
        {
            new_mat.a[i][j] = a[i][j] * num;
        }
    }
    return new_mat;
}

Файл тестирование класса Teting of the class:

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
#include "classMatrix.h"
#include <iostream>
 
using namespace std;
 
int main()
{
    try
    {
        Matrix A(3, 3);
        Matrix B(3, 3);
        cin >> A >> B;
        cout << "A * B = " << '\n' << A * B << '\n';
        cout << "A + B = " << '\n' << A + B << '\n';
        cout << "A - B = " << '\n' << A - B << '\n';
        cout << "A * 2 = " << '\n' << A * 2 << '\n';
        Matrix C;
    }
    catch (Matrix::IrrelevantSizes)
    {
        cout << "Matrices have irrelevant sizes." << '\n';
    }
    catch (Matrix::NonexistentElement)
    {
        cout << "Such element does not exist." << '\n';
    }
    return 0;
}
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
07.02.2012, 12:39     Класс Матрица
Еще ссылки по теме:

Класс матрица C++
C++ класс матрица
Класс Матрица C++

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

Или воспользуйтесь поиском по форуму:
Felsurt
5 / 5 / 0
Регистрация: 06.02.2012
Сообщений: 19
07.02.2012, 12:39     Класс Матрица #20
я бы считал определитель рекурсивно через разложение по строке

Цитата Сообщение от Игорь Миронюк Посмотреть сообщение
А еще думаю сделать конструктор матрицы, полученной из данной вычеркиванием определенной строки и столбца.
да, это удобный функционал
только его лучше реализовывать не конструктором, а методом класса (getMinor), так будет логичней


ну и обычно в заголовочниках пишут так
C++
1
friend std::istream& operator>>(std::istream& in, Matrix& mat);
и тогда никакой using там и не нужен

C++
1
void operator=(const Matrix& mat);
здесь очень грубая ошибка есть
оператор равно всегда должен возвращать ссылку на объект

C++
1
2
3
4
Matrix &operator=(const Matrix& mat) {
 ...
 return *this;
}
такое объявление позволяет писать подобный код:
C++
1
a = b = c;
и именно такого поведения программист ожидает от оператора равно любого класса.
это аналогично операторам ввода/вывода, которые так же должны возвращать ссылку на свой левый аргумент, что позволяет писать "конвейеры".

в методе element вы проверяете, что индекс не больше допустимого, но не проверяете обратного (меньше допустимого)
ну и для удобства, как мне кажется, для доступа к элементам можно было бы перегрузить оператор круглых скобок
именно круглых, т.к. оператор квадратных скобок обязан всегда принимать только один аргумент

если есть оператор + и оператор =, то почему бы не реализовать оператор +=? (аналогично к остальным операторам)
кстати, обычно реализуют оператор = и +=, как методы класса, а оператор + делают внешним реализованным через эти два примерно так

C++
1
2
3
Matrix operator+(const Matrix& mat) const {
   return Matrix(*this) += mat;
}
вы дали возможность пользователю умножить матрицу на число, но не дали возможности умножить число на матрицу
C++
1
2
3
4
Matrix m(...);
double d = ...;
m * d;  // OK
d * m;  // Fail
ну и все же возвращаясь к тому, что в классе должен быть лишь необходимый минимум
ваш класс задал оператор == и я, как бы того не хотел, теперь не смогу изменить критерий сравнения матриц (потому что среди перегруженный функций предпочтение всегда компилятор отдает методу класса)
и если вдруг в моей программе не важно равенство элементов матрицы, а лишь важно равенство их размерностей, то мне придется писать длинное некрасивое условие if всегда, когда понадобиться сравнить объекты
а вот если бы вы были чуточку милосердны и подумали о разработчиках, которые, быть может, станут пользоваться вашим классом, то вынесли бы оператор == за его пределы и объявили вообще в отдельном файле
и тогда бы я мог его подключить, а мог бы написать свой оператор и все были бы счастливы
(ну это не говоря о том, что свой класс, по хорошему, надо поместить в свое пространство имен, тогда можно все в одном файле объявить)
Yandex
Объявления
07.02.2012, 12:39     Класс Матрица
Ответ Создать тему
Опции темы

Текущее время: 00:22. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru