Приклад створення шаблонного класу Матриця з динамічним виділенням пам’яті
У прикладі демонструється створення шаблонного класу MATRIX, який реалізує матрицю розміром m*n. Пам’ять для матриці виділяється динамічно.
За даним прикладом можна створювати та використовувати власні класи, що містять структури даних в яких пам’ять виділяється динамічно.
У класі реалізовано:
- прихована (private) внутрішня змінна M типу “покажчик на покажчик”. Ця змінна визначає матрицю. Пам’ять для матриці буде виділятись динамічно;
- дві цілочисельні внутрішні private-змінні m, n. Ці змінні визначають розмірність матриці M;
- конструктор за замовчуванням (без параметрів);
- конструктор з двома параметрами MATRIX(int, int). Цей конструктор створює матрицю розміром m*n. У конструкторі виділяється пам’ять для стовпців та рядків матриці. Значення кожного елементу матриці встановлюється в 0;
- конструктор копіювання MATRIX(MATRIX&). Цей конструктор необхідний для створення копії об’єкту-матриці з іншого об’єкту-матриці;
- методи читання/запису елементів матриці GetMij(), SetMij();
- метод Print(), що виводить матрицю;
- оператор копіювання operator=(MATRIX&). Цей оператор перевантажує оператор присвоєння = і призначений для коректного копіювання об’єктів типу obj2=obj1;
- деструктор.
Реалізація класу для додатку типу Console Application має такий вигляд
#include <iostream> using namespace std; // шаблонний клас Матриця template <typename T> class MATRIX { private: T** M; // матриця int m; // к-сть рядків int n; // к-сть стовпців public: // конструктори MATRIX() { n = m = 0; M = nullptr; // необов'язково } // конструктор з двома параметрами MATRIX(int _m, int _n) { m = _m; n = _n; // Виділити пам'ять для матриці // Виділити пам'ять для масиву покажчиків M = (T**) new T*[m]; // к-сть рядків, к-сть покажчиків // Виділити пам'ять для кожного покажчика for (int i = 0; i < m; i++) M[i] = (T*)new T[n]; // Заповнити масив M нулями for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) M[i][j] = 0; } // Конструктор копіювання - обов'язковий MATRIX(const MATRIX& _M) { // Створюється новий об'єкт для якого виділяється пам'ять // Копіювання даних *this <= _M m = _M.m; n = _M.n; // Виділити пам'ять для M M = (T**) new T*[m]; // к-сть рядків, к-сть покажчиків for (int i = 0; i < m; i++) M[i] = (T*) new T[n]; // заповнити значеннями for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) M[i][j] = _M.M[i][j]; } // методи доступу T GetMij(int i, int j) { if ((m > 0) && (n > 0)) return M[i][j]; else return 0; } void SetMij(int i, int j, T value) { if ((i < 0) || (i >= m)) return; if ((j < 0) || (j >= n)) return; M[i][j] = value; } // метод, що виводить матрицю void Print(const char* ObjName) { cout << "Object: " << ObjName << endl; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) cout << M[i][j] << "\t"; cout << endl; } cout << "---------------------" << endl << endl; } // оператор копіювання - обов'язковий MATRIX operator=(const MATRIX& _M) { if (n > 0) { // звільнити пам'ять, виділену раніше для об'єкту *this for (int i = 0; i < m; i++) delete[] M[i]; } if (m > 0) { delete[] M; } // Копіювання даних M <= _M m = _M.m; n = _M.n; // Виділити пам'ять для M знову M = (T**) new T*[m]; // к-сть рядків, к-сть покажчиків for (int i = 0; i < m; i++) M[i] = (T*) new T[n]; // заповнити значеннями for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) M[i][j] = _M.M[i][j]; return *this; } // Деструктор - звільняє пам'ять, виділену для матриці ~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"); }
Результат роботи програми
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 ---------------------
Підсумок. Якщо пам’ять в класі виділяється динамічно, то обов’язково потрібно реалізовувати власний конструктор копіювання та оператор копіювання.
⇑
Зв’язані теми
⇑