MATRIX() { if (n > 0) { // звільнити виділену пам'ять для кожного рядка for (int i = 0; i < m; i++) delete[] M[i]; } if (m > 0) delete[] M; } }; void main() { // тест для класу MATRIX MATRIX<int> M(2, 3); M.Print("M"); // Заповнити матрицю значеннями за формулою int i, j; for (i = 0; i < 2; i++) for (j = 0; j < 3; j++) M.SetMij(i, j, i + j); M.Print("M"); MATRIX<int> M2 = M; // виклик конструктора копіювання M2.Print("M2"); MATRIX<int> M3; // виклик оператора копіювання - перевірка M3 = M; M3.Print("M3"); MATRIX<int> M4; M4 = M3 = M2 = M; // виклик оператора копіювання у вигляді "ланцюжка" M4.Print("M4"); }ПРИВАТНЕ АКЦІОНЕРНЕ ТОВАРИСТВО «ВИЩИЙ НАВЧАЛЬНИЙ ЗАКЛАД “МІЖРЕГІОНАЛЬНА АКАДЕМІЯ УПРАВЛІННЯ ПЕРСОНАЛОМ”» ФАКУЛЬТЕТ КОМП’ЮТЕРНО-ІНФОРМАЦІЙНИХ ТЕХНОЛОГІЙ Курсова робота з дисципліни: " Об’єктно-орієнтоване програмування" на тему: "Розробка класу матриця" Спеціальність:121 Студент(ка):Логiнов О.С. Викладач:Тінькова Ю.О. 2022 р. Поняття Матриця в європейській науці було введено в роботах У. Гамільтона та А. Келі у середині XIX століття. У 1980-ті роки, коли масового поширення набули персональні комп'ютери, обчислювальні та розрахунково-алгоритмічні завдання стали займати другорядне місце. Комп'ютер перестав сприйматися як простий обчислювач, він перетворився на середовище вирішення різних прикладних завдань обробки та маніпулювання даними. На перший план вийшли завдання організації простої і зручної людино-машинної взаємодії, розробка програм із зручним графічним інтерфейсом, створення автоматизованих систем управління та ін. що ускладнювало процес створення програмного забезпечення. Також збільшувалися розміри програм, що вимагало залучення чимало програмістів і додаткових ресурсів в організацію їх узгодженої роботи. В цей момент провідним при розробці програм став об'єктно-орієнтований підхід, який заснований на використанні у програмах набору моделей об'єктів, що описують предметну область задачі, що вирішується. Такі моделі називають об'єктними або об'єктно-інформаційними. Людство у своїй діяльності (науковій, освітній, технологічній, культурній) постійно створює і використовує моделі для опису навколишнього світу (макет житлового комплексу, що будується, модель літака, ескізи картин і т.д.). Моделі дозволяють представити в наочній формі об'єкти, взаємозв'язки між ними та процеси. Основою об'єктно-інформаційної моделі є. Об'єкт – це частина навколишньої дійсності, сприймана людиною як єдине ціле. Об'єкти можуть бути матеріальними (предмети та явища) та нематеріальними (ідеї та образи), наприклад, матриця – це матеріальний об'єкт. Кожен об'єкт характеризується безліччю властивостей. Інформаційна модель об'єкта виділяє з цієї множини лише деякі властивості, суттєві для вирішення конкретної задачі, що дозволяють відокремити цей об'єкт від інших. Об'єкти можуть бути в різних станах. Стан об'єкта характеризується переліком всіх його властивостей та їх поточними значеннями. Безліч об'єктів з однаковим набором властивостей та поведінкою називається класом. Інкапсуляція даних Цей термін включає логічне зв'язування даних з конкретною операцією. Вона так само означає, що вони є не глобальними доступними всій програмі, а локальними – доступними тільки малої її частини. Інкапсуляція також автоматично має на увазі захист даних. Саме для цього призначена структура class С++. У класі управління функціональними деталями об'єкта здійснюється за допомогою специфікаторів private, public, protected. Для створення об'єктів класу є спеціальні методи, які називають конструкторами. Вони потрібні для коректної ініціалізації об'єкта. Наприклад, при створенні матриці заданих розмірів конструктор повинен виділити пам'ять зберігання елементів цієї матриці. Знищенням об'єкта займається спеціальний метод класу, який називають деструктором. Його завдання – звільнити ресурси, які займає об'єкт (закрити використовувані файли, з'єднання з базами даних тощо). Одним із принципів об'єктно-орієнтованого програмування (ООП) – інкапсуляція. Цей термін характеризує приховування окремих деталей внутрішнього пристрою класу від зовнішніх щодо нього об'єктів чи користувачів. Клас «Матриця» (Matrix) містить змінні, доступ яких може бути здійснено лише з методів класу. Такий підхід використовується для того, щоб захистити змінні від несанкціонованого доступу.Наприклад, якщо дати можливість програмісту, який буде працювати з об'єктом класу Matrix, змінювати напряму значення змінних для зберігання розміру матриці, ці значення можуть стати некоректними (негативними, дуже великими, або не відповідними дійсним розмірам). А, виконуючи те саме за допомогою методів класу, можна включити в них перевірку коректності введених значень. Для нашого класу таким способом може бути спосіб введення матриці. Ієрархія класів У випадку можна уявити собі ієрархію класів як родовід в генеалогічному дереві, де клас С++ є шаблоном для створення класів-нащадків. Об'єкти, одержані з опису класу, називають екземплярами цього класу. Можна створити ієрархію класів з класом-батьком та кількома класами-нащадками. Основою цього є похідні класи. успадкування Успадкування в ООП дозволяє класу отримувати засоби іншого класу об'єктів. Батьківський клас є шаблоном для похідного класу; цей шаблон можна змінювати у різний спосіб. Спадкування є важливим положенням, оскільки воно дозволяє повторно використовувати визначення класу без значних змін коду. Поліморфізм Будується на описаній вище концепції спадкування. Програма посилає те саме повідомлення як об'єкту батьківського класу, так і всім об'єктам похідних класів. І батьківський клас, і класи-нащадки дадуть відповідь відповідним чином. Поліморфізм дозволяє доповнювати вже існуючі частини програми. Віртуальні функції Віртуальні функції визначаються батьківському класі, а похідних класах відбувається довизначення цих функцій й них створюються нові реалізації. Під час роботи з віртуальними функціями повідомлення передаються як вказівники, які вказують на об'єкт замість прямої передачі об'єкту. Віртуальні функції використовують таблицю адресної інформації. Ця таблиця ініціалізується під час виконання з допомогою конструктора. Конструктор викликається щоразу, коли створюється об'єкт його класу. Завдання конструктора у разі полягає у зв'язуванні віртуальної функції з таблицею адресної інформації. Під час компіляції адреса віртуальної функції невідома; натомість їй відводиться позиція у таблиці адрес. Ця позиція міститиме адресу функції . Крім структурних показників класу приховування підлягає й реалізація операцій класу. Для користувача немає потреби знати, як реалізований той чи інший метод. Потрібно знати тільки те, що метод виконує, як до нього звернутися і як скористатися результатом його роботи. Наприклад, визначник квадратної матриці можна обчислити різними способами: методом винятків Гауса або за формулою Лапласа - розкладання рядком або стовпцем. Для користувача не має значення, який алгоритм закладено у методі класу. Структура даних Як відомо, структура даних є модель даних у вигляді математичної структури. S = (M1, …, Mk, p1,…,pn). Відповідно до цього можна навести такі визначення: Структура даних Матриці A = (aij), где i = 1..n; j = 1..n есть Sa = (Ma, p1a, p2a), Где Ma = {a11, a12, …, ann-1,ann} – базисна множина, – відносини слідування. Для структури даних Матриця пропонується реалізувати такі операції: порівняння: складання/віднімання матриць: множення матриць. Нехай aij – елементи матриці A, а bij – елементи матриці B. Лінійні операції: Множення матриці A на число λ (позначення: λA) полягає у побудові матриці B, елементи якої отримані шляхом множення кожного елемента матриці A на це число, тобто кожен елемент матриці B дорівнює bij = λaij Додавання матриць A + B є операція знаходження матриці C, всі елементи якої дорівнюють попарній сумі всіх відповідних елементів матриць A і B, тобто кожен елемент матриці C дорівнює cij = aij + bij Віднімання матриць A − B визначається аналогічно до складання, це операція знаходження матриці C, елементи якої cij = aij - bij Додавання та віднімання допускається тільки для матриць однакового розміру.. Множення матриць (позначення: AB, рідше зі знаком множення ) — є операція обчислення матриці C, елементи якої рівні сумі творів елементів у відповідному рядку першого множника та стовпці другого. У першому множнику має бути стільки ж стовпців, скільки рядків у другому. Якщо матриця A має розмірність , B — то розмірність їх твору AB = C є. Основні характеристики матриць: -кількість рядків -кількість стовпців -масив елементів Характеристики класу Матриця Клас має приватні та загальнодоступні члени-дані та члени-функції (методи). Для зберігання компонентів матриці використовується одновимірний масив елементів типу параметра шаблону. Для створення об'єкта передбачено три конструктори: конструктор за замовчуванням, конструктор з параметрами, конструктор копіювання та деструктор. Для виконання безлічі матричних операцій створено перевантажені операції: привласнення (=), додавання (+), віднімання (-), множення (*) і т.п. На базі операторів введення/виводу С++ розроблені функції введення матриць з потоку та виведення їх у потік, що передбачають у разі файлового введення/виводу як текстову форму зберігання, так і бінарну. Доступ до членів-даним класу – числу рядків та стовпців матриці здійснюється за допомогою методів size_row( ) та size_col( ). Доступ до елементів матриці створено перевантажений оператор виклику функції operator( ) (dim x, dim x), де dim – перевизначений тип unsigned char. Виклик функції використовується як оператор індексування, який приймає два аргументи. Аналогічно створено оператора виклику функції з одним аргументом operator( ) (dim x). Для цього класу – це дуже важливі перевантажені оператори, т.к. вони використовуються у всіх функціях та операторах, у яких відбувається звернення до елементів матриці. Опис функцій, конструкторів та деструкторів класу: Конструктор за замовчуванням Matrix( ): Конструктор за замовчуванням створює матрицю нульового. розміру. Надалі розмір цієї матриці можна змінити за допомогою функції newsize (i, j).Конструктор із параметрами Matrix(dim, dim=1): Це звичайний конструктор з параметрами, який приймає як параметри розміри матриці та створює одновимірний динамічний масив розміром m*n, де m – число рядків, а n – число стовпців матриці. З метою можливості використовувати його для створення векторів, другий параметр конструктора заданий як замовчується зі значенням 1. Для початкової ініціалізації елементів матриці нулями використовується функція setmem( ). Конструктор копіювання Matrix (const Matrix &): Конструктор приймає як параметр посилання на об'єкт класу (на існуючу матрицю), визначає її розмір, виділяє для неї пам'ять і копіює в цю пам'ять вміст матриці, що приймається за посиланням. Таким чином створюється точна копія матриці з поточними значеннями її елементів. Деструктор Результат виконання програми Object: M 0 0 0 0 0 0 --------------------- Object: M 0 1 2 1 2 3 --------------------- Object: M2 0 1 2 1 2 3 --------------------- Object: M3 0 1 2 1 2 3 --------------------- Object: M4 0 1 2 1 2 3 --------------------- Реалізація класу матриця const double eps = 1e-9; class matrix { private: double **a; int n, m; public: // матриця без елементів matrix () { a = 0; n = 0; m = 0; } // матриця NxM, якщо E, то одинична, інакше нульова matrix (int N, int M, bool E = 0) { n = N; m = M; a = new double *[n]; for (int i = 0; i < n; ++ i) { a[i] = new double[m]; for (int j = 0; j < m; ++ j) a[i][j] = (i == j) * E; } } // матриця із елементів array, якщо horizontal, то горизонтальна, інакше вертикальна matrix (double array[], int N, bool horizontal) { if (horizontal) { n = 1; m = N; a = new double *[1]; a[0] = new double[m]; for (int i = 0; i < m; ++ i) a[0][i] = array[i]; } else { n = N; m = 1; a = new double *[n]; for (int i = 0; i < n; ++ i) { a[i] = new double[1]; a[i][0] = array[i]; } } } int N () { return n; } int M () { return m; } double* operator [] (int index) { return getRow (index); } // отримати рядок матриці double* getRow (int index) { if (index >= 0 && index < n) return a[index]; return 0; } //отримати стовпчик матриці double* getColumn (int index) { if (index < 0 || index >= m) return 0; double * c = new double [n]; for (int i = 0; i < n; ++ i) c[i] = a[i][index]; return c; } // поміняти місцями два рядки void swapRows (int index1, int index2) { if (index1 < 0 || index2 < 0 || index1 >= n || index2 >= n) return ; for (int i = 0; i < m; ++ i) swap (a[index1][i], a[index2][i]); } // поміняти місцями два стовпці void swapColumns (int index1, int index2) { if (index1 < 0 || index2 < 0 || index1 >= m || index2 >= m) return ; for (int i = 0; i < n; ++ i) swap (a[i][index1], a[i][index2]); } // приписування матриці b до поточної матриці справа matrix concateMatrix (matrix & b) { if (n != b.N ()) return matrix (); matrix c = matrix (n, m + b.M ()); for (int i = 0; i < n; ++ i) { for (int j = 0; j < m; ++ j) c[i][j] = a[i][j]; for (int j = 0; j < b.M (); ++ j) c[i][j + m] = b[i][j]; } return c; } //видалення стовпців index1 по index2 matrix eraseColumns (int index1, int index2) { matrix c = matrix (n, m - (index2 - index1 + 1)); for (int j = 0; j < index1; ++ j) for (int i = 0; i < n; ++ i) c[i][j] = a[i][j]; for (int j = index2 + 1; j < m; ++ j) for (int i = 0; i < n; ++ i) c[i][j - index2 - 1 + index1] = a[i][j]; return c; } }; // прочитати матрицю з консолі matrix scanMatrix () { int n, m; scanf ("%d%d", & n, & m); matrix a = matrix (n, m); for (int i = 0; i < n; ++ i) for (int j = 0; j < m; ++ j) scanf ("%lf", & a[i][j]); return a; } // вивести матрицю void printMatrix (matrix & a) { for (int i = 0; i < a.N (); ++ i) { for (int j = 0; j < a.M (); ++ j) printf ("%5.3lf ", a[i][j]); puts (""); } } // скласти дві матриці matrix add (matrix & a, matrix & b) { if (a.N () != b.N () || a.M () != b.M ()) return matrix (); matrix c = matrix (a.N (), b.M ()); for (int i = 0; i < a.N (); ++ i) for (int j = 0; j < a.M (); ++ j) c[i][j] = a[i][j] + b[i][j]; return c; } // множення матриці на число matrix mul (matrix & a, double k) { matrix c = matrix (a.N (), a.M ()); for (int i = 0; i < a.N (); ++ i) for (int j = 0; j < a.M (); ++ j) c[i][j] = a[i][j] * k; return c; } // множення двох матриць matrix mul (matrix & a, matrix & b) { if (a.M () != b.N ()) return matrix (); matrix c = matrix (a.N (), b.M ()); for (int i = 0; i < a.N (); ++ i) for (int j = 0; j < b.M (); ++ j) for (int k = 0; k < a.M (); ++ k) c[i][j] += a[i][k] * b[k][j]; return c; } //транспонування матриці matrix transp (matrix & a) { matrix c = matrix (a.M (), a.N ()); for (int i = 0; i < a.N (); ++ i) for (int j = 0; j < a.M (); ++ j) c[j][i] = a[i][j]; return c; } Висновок В результаті виконання курсового проекту було розроблено клас Матриця для вирішення найпростіших завдань. Число цих функцій порівняно невелике, проте можна легко додати до цього класу складніші функції, побудовані на базі вже наявних. У процесі виконання курсової роботи було виконано: - на першому етапі роботи було проаналізовано завдання та визначено перелік питань, які були вирішені в даній роботі, визначення того, що, власне, виконуватиме програма, що розробляється, не розглядаючи конкретну реалізацію цих функцій; - розробка алгоритму програми, що розробляється; - розробка програми та інтерфейсу користувача; - Здійснено налагодження програми. Джерела: https://www.bestprog.net/ru/2019/08/23/c-an-example-of-creating-a-template-class-matrix-dynamic-memory-allocation-ru/ https://studbooks.net/2076720/informatika/osnovnye_terminy_polozheniya https://zinvapel.github.io/it/prog/oop/2017/10/30/oop-base/ https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85 https://ru.wikipedia.org/wiki/%D0%9C%D0%B0%D1%82%D1%80%D0%B8%D1%86%D0%B0_(%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0) http://iwanoff.inf.ua/algorithmization_2/LabTraining01.html http://hardfire.ru/class_matrix |