Managed (керовані) та unmanaged (некеровані) класи у Visual C++. Огляд відмінностей роботи. Приклади реалізації managed та unmanaged класів
Зміст
- 1. Які види класів існують у Visual C++? Які особливості використання різних видів класів?
- 2. Приклад використання класу, що описує масив з n чисел
- Зв’язані теми
Пошук на інших ресурсах:
1. Які види класів існують у Visual C++? Які особливості використання різних видів класів?
У системі Visual C++ використовуються два види класів:
- unmanaged-класи (native-класи). Це класичний варіант опису та використання класу. Такі класи використовуються в поєднанні з покажчиками ‘*’;. Пам’ять для такого покажчика виділяється з допомогою оператора new;
- managed-класи. Це класи, що призначені для використання в середовищі CLR (Common Language Runtime). Такі класи розміщуються в пам’яті, яка використовується і керується середовищем CLR. Об’єкти цих класів розміщуються в динамічній пам’яті. Якщо потрібно описати покажчик на managed-клас, то для цього використовується символ ‘^’. Пам’ять для такого покажчика виділяється утилітою gcnew.
Робота з покажчиками на клас детально описується в темах:
- Покажчики. Некеровані покажчики і масиви. Покажчик на структуру. Покажчик на клас
- Покажчики. Складені native та managed типи даних. Керовані покажчики в середовищі CLR. Виділення пам’яті. Кваліфікатори ref та value. Керовані покажчики (^) на структури, класи.
2. Приклад використання класу, що описує масив з n чисел
Нижче наведено приклади реалізації класів двох видів:
- unmanaged-класу (native-класу);
- managed-класу.
За даними прикладами можна розробляти власні класи.
2.1. Unmanaged (некерований) клас
2.1.1. Робота з методами класу з допомогою об’єкту класу
У прикладі реалізовано unmanaged-клас MyArrayUnmanaged, що представляє собою масив чисел типу double розмірністю n.
У класі описуються такі внутрішні змінні:
- n – поточна кількість елементів масиву (довжина масиву);
- A – масив чисел типу double.
У класі реалізовано такі конструктори:
- конструктор за замовчуванням MyArrayUnmanaged(). Цей конструктор занулює значення n;
- конструктор, що ініціалізує значення n та масив A. Конструктор має 1 параметр.
У класі реалізовано такі методи:
- GetN() – читає поточне значення n;
- SetN() – встановлює нове значення n, автоматично занулюється масив A. Пам’ять для масиву перевизначається;
- GetAi() – повертає значення заданого елементу масиву;
- SetAi() – встановлює нове значення заданого елементу масиву;
- GetArrayPtr() – демонстраційний метод, що повертає unmanaged-покажчик (*) на масив.
class MyArrayUnmanaged { // оголошення масиву в unmanaged класі int n; double *A; public: MyArrayUnmanaged(void); // конструктор за замовчуванням ~MyArrayUnmanaged(void); // деструктор MyArrayUnmanaged(int nn) // конструктор з 1 параметром { n = nn; // виділення пам'яті для масиву A = new double[n]; // заповнення масиву значеннями for (int i=0; i<n; i++) A[i] = i; } // методи класу // взяти значення n int GetN(void) { return n; } // встановити нове значення n void SetN(int nn) { // звільнити пам'ять, виділену для старого масиву if (n>0) delete A; n = nn; // виділити пам'ять для нового масиву A = new double[n]; // занулити значення новоствореного масиву for (int i=0; i<n; i++) A[i] = 0; } // повернути значення масиву, що знаходиться в позиції i double GetAi(int i) { return (double)A[i]; } // встановити нове значення масиву, що знаходиться в позиції i void SetAi(int i, double x) { A[i] = x; } // повернути покажчик на масив double * GetArrayPtr(void) { return (double *)A; } }; // реалізація конструкторів класу // Конструктор класу за замовчуванням MyArrayUnmanaged::MyArrayUnmanaged(void) { n = 0; } // Деструктор класу MyArrayUnmanaged::~MyArrayUnmanaged(void) { if (n>0) delete A; }
Демонстрація роботи з класом в іншому методі (програмному коді)
// Демонстрація роботи з класом MyArrayUnmanaged MyArrayUnmanaged MA; // об'єкт класу, викликається конструктор без параметрів int d; double x; d = MA.GetN(); // d = 0 MyArrayUnmanaged MA2(15); // викликається конструктор з 1 параметром d = MA2.GetN(); // d = 15 MyArrayUnmanaged MA3 = 25; // викликається конструктор з 1 параметром d = MA3.GetN(); // d = 25 x = MA3.GetAi(5); // x = 5.0 MA3.SetAi(5, -3.45); // змінити значення в комірці 5 масиву MA3 x = MA3.GetAi(5); // x = -3.45 // використання методу GetArrayPtr() double * B; // unmanaged-покажчик на double B = MA3.GetArrayPtr(); // B вказує на масив A об'єкту MA3 x = B[3]; // x = 3.0 x = B[5]; // x = -3.45 // використання методу SetN() MA3.SetN(5); d = MA3.GetN(); // d = 5 x = MA3.GetAi(3); // x = 0
2.1.2. Робота з методами класу з допомогою покажчика (*) на клас
Продемонстрована робота з unmanaged-покажчиком на клас.
MyArrayUnmanaged * pA; // оголосити покажчик на клас pA = new MyArrayUnmanaged(10); // викликається конструктор з 1 параметром int d; double x; d = pA->GetN(); // d = 10 x = pA->GetAi(3); // x = 3
2.2. Приклад реалізації managed (керованого) класу
У наведеному нижче прикладі реалізовано managed-клас CMyArray, що реалізує масив з n дійсних (double) чисел. Розмірність масиву змінюється динамічно в залежності від потреби.
У класі реалізовано такі внутрішні (private) змінні:
- n – поточна кількість елементів масиву;
- A – масив чисел.
Клас містить 2 конструктори:
- CMyArray() без параметрів. Це є конструктор за замовчуванням. У цьому конструкторі значення n встановлюється рівним нулю;
- CMyArray() з одним параметром, що рівний розміру масиву n. Тут значення елементів масиву встановлюється рівним номеру індексу масиву.
Методи класу наступні:
- GetN() – отримати поточну довжину масиву n;
- SetN() – встановити нове значення n і занулити значення елементів масиву A;
- GetAi() – отримати поточне значення елементу масиву з індексом i;
- GetArrayA() – отримати цілий масив елементів;
- SetAi() – встановити нове значення в елемент масиву з індексом i.
Реалізація класу міститься в декількох модулях (файлах):
- файл MyArray.h – містить код класу CMyArray;
- файл MyArray.cpp – містить реалізацію методів класу. У даному випадку цей модуль містить реалізацію конструкторів класу. Реалізація інших методів описується в самому класі.
Текст модуля MyArray.h наступний:
// managed клас CMyArray ref class CMyArray { // оголошення масиву розміром n в managed-класі int n; array <double^> ^A; public: // Конструктор за замовчуванням CMyArray(void); // конструктор з одним параметром CMyArray(int nn); // Методи класу // взяти значення n int GetN(void) { return n; } // встановити нове значення n void SetN(int nn) { if (n>0) delete A; n = nn; // нове значення A = gcnew array <double^>(n); for (int i=0; i<n; i++) A[i] = gcnew double; for (int i=0; i<n; i++) A[i] = (double)0; } // взяти елемент масиву з індексом i (i = 1..n-1) double GetAi(int i) { return (double)A[i]; } // взяти покажчик на масив array <double^> ^ GetArrayA(void) { return A; } // встановити нове значення в елемент масиву з індексом i (i=1..n-1) void SetAi(int i, double nx) { A[i] = nx; } };
Текст модуля MyArray.cpp наступний:
#include "StdAfx.h" #include "MyArray.h" // конструктор за замовчуванням CMyArray::CMyArray(void) { n = 0; } // конструктор з 1 параметром CMyArray::CMyArray(int nn) { n = nn; // виділення пам'яті для масиву (перевиділення) A = gcnew array <double ^>(n); // виділення пам'яті для кожної комірки масиву for (int i=0; i<n; i++) A[i] = gcnew double; // заповнення значеннями елементів масиву for (int i=0; i<n; i++) A[i] = (double)i; }
2.2.1. Робота з методами класу з допомогою об’єкту класу
Щоб використовувати даний клас в інших модулях (файлах) потрібно підключити модуль MyArray.h
#include "MyArray.h"
Наведений нижче програмний код демонструє використання методів класу CMyArray.
// Демонстрація роботи з об'єктом managed-класу // 1. Виклик конструктора без параметрів (викликається автоматично) CMyArray MA; // об'єкт класу CMyArray, викликається конструктор без параметрів CMyArray()... int d; d = MA.GetN(); // d = 0 // 2. Виклик конструктора з 1 параметром при створенні об'єкту, спосіб 1 CMyArray MA2(15); // викликаєтсья конструктор CMyArray(15) int d2 = MA2.GetN(); // d2 = 15 double x; x = MA2.GetAi(5); // x = 5.0 // 3. Виклик конструктора з 1 параметром при створенні об'єкту, спосіб 2 CMyArray MA3 = 20; // викликається конструктор CMyArray(20) int d3; d3 = MA3.GetN(); // d3 = 20 x = MA3.GetAi(18); // x = 18.0 // 4. Демонстрація повернення масиву з методу класу GetArrayA CMyArray MA4 = 30; // в масиві 30 елементів array <double^> ^B; B = MA4.GetArrayA(); // Взяти цілий масив A з класу x = (double)B[22]; // x = 22.0 // 5. Метод SetAi CMyArray MA5 = 10; // оголосити масив з 10 елементів MA5.SetAi(3, 2.85); // виклик методу SetAi x = MA5.GetAi(3); // x = 2.85 // 6. Метод SetN MA5.SetN(30); d = MA5.GetN(); // d = 30 x = MA5.GetAi(3); // x = 0
Пояснимо деякі фрагменти коду. При оголошенні об’єкту класу
CMyArray MA;
викликається конструктор за замовчуванням CMyArray().
Якщо потрібно вказати розмірність масиву при його оголошенні, то для класу CMyArray можна написати
CMyArray MA2(10);
або
CMyArray MA2 = 10;
де число 10 означає розмірність масиву.
Методи обробки даних класу описуються в розділі public. Виклик методів здійснюється стандартним способом з допомогою символу ‘ . ‘.
2.2.2. Робота з методами класу з допомогою покажчика (^) на клас
Також можна описувати покажчик на managed-клас. Наведений нижче код демонструє використання покажчика на клас CMyArray.
// managed-покажчик на клас CMyArray ^ pA; pA = gcnew CMyArray(10); // виділення пам'яті для класу (масиву з 10 елементів), виклик конструктора double x; x = pA->GetAi(5); // x = 5, доступ до методів класу
У наведеному вище коді в рядку
pA = gcnew CMyArray(10);
викликається конструктор CMyArray() з одним параметром (параметризований констуктор). В конструкторі здійснюється виділення пам’яті для масиву та заповнення елементів значеннями.