Managed (управляемые) и unmanaged (неуправляемые) классы в Visual C++. Обзор особенностей работы. Примеры реализации managed и unmanaged классов

Managed (управляемые) и unmanaged (неуправляемые) классы в Visual C++. Обзор особенностей работы. Примеры реализации managed и unmanaged классов


Содержание


1. Какие виды классов существуют в Visual C++? Какие особенности использования разных видов классов?

В системе Visual C++ используются два вида классов:

  • unmanaged-классы (native-классы). Это классический вариант описания и использования класса. Такие классы используются в объединении с managed-указателями (*). Память для таких указателей выделяется с помощью оператора new;
  • managed-классы. Это классы, которые предназначены для использования в среде CLR (Common Language Runtime). Такие классы размещаются в памяти, которая используется и управляется средой CLR. Объекты этих классов размещаются в динамической памяти. Если нужно описать указатель на managed-класс, то для этого используется символ ‘^‘. Память для такого указателя выделяется утилитой gcnew.

Работа с указателями на класс подробно описывается в темах:

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() с одним параметром (параметризированный конструктор). В конструкторе осуществляется выделение памяти для массива и заполнение элементов массива значениями.


Связанные темы