Managed (управляемые) и unmanaged (неуправляемые) классы в Visual C++. Обзор особенностей работы. Примеры реализации managed и unmanaged классов
Содержание
- 1. Какие виды классов существуют в Visual C++? Какие особенности использования разных видов классов?
- 2. Пример использования класса, который описывает массив из n чисел
- Связанные темы
Поиск на других ресурсах:
1. Какие виды классов существуют в Visual C++? Какие особенности использования разных видов классов?
В системе Visual C++ используются два вида классов:
- unmanaged-классы (native-классы). Это классический вариант описания и использования класса. Такие классы используются в объединении с managed-указателями (*). Память для таких указателей выделяется с помощью оператора new;
- managed-классы. Это классы, которые предназначены для использования в среде CLR (Common Language Runtime). Такие классы размещаются в памяти, которая используется и управляется средой CLR. Объекты этих классов размещаются в динамической памяти. Если нужно описать указатель на managed-класс, то для этого используется символ ‘^‘. Память для такого указателя выделяется утилитой gcnew.
Работа с указателями на класс подробно описывается в темах:
- Указатели. Часть 3. Неуправляемые (*) указатели и массивы. Указатель на структуру. Указатель на класс;
- Указатели. Часть 6. Составные 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; } // получить unmanaged-указатель на массив 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.Get(); // d = 0 MyArrayUnmanaged MA2(15); // вызывается конструктор с 1 параметром d = MA2.Get(); // 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 * p; // объявить указатель на класс p = 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 следующий:
#pragma once // 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. Работа с методами класса с помощью объекта класса
Чтобы использовать класс CMyArray в других модулях (файлах) нужно подключить модуль 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 CMyArrayA 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 p; p = gcnew CMyArray(10); // выделение памяти для класса (массива с 10 элементов), вызывается конструктор double x; x = p->GetAi(5); // x = 5, доступ к методам класса
В приведенном выше коде в строке
pA = gcnew CMyArray(10);
вызывается конструктор CMyArray() с одним параметром (параметризированный конструктор). В конструкторе осуществляется выделение памяти для массива и заполнение элементов массива значениями.