Структуры. Часть 3. Работа с managed-структурами в среде CLR. Квалификаторы ref и value. Объявление структурных переменных. Массивы managed-структурных переменных. Инициализация managed-структур

Структуры. Часть 3. Работа с managed-структурами в среде CLR. Квалификаторы ref и value. Объявление структурных переменных. Массивы managed-структурных переменных. Инициализация managed-структур

Эта тема базируется на теме:

Структуры. Часть 1. Составные типы данных. Структурная переменная. Структуры в среде CLR. Объявление и инициализация структурной переменной


Содержание



1. Какие квалификаторы используются с managed-структурами в среде CLR?

В среде CLR можно использовать три вида структур:

  • native-структуры. Это классические структуры C/C++, которые используются в предшествующих версиях разных сред программирования. Такие структуры объявляются без квалификатора;
  • managed-структуры. Это структуры, предназначенные для работы в управляемой памяти, которая используется в среде CLR. В этом случае значения указателей не может выходить за пределы выделенной программе памяти.

С managed-структурами в Visual C++/CLR используются два квалификатора (ключевых слова):

  • квалификатор (ключевое слово) ref. Этот квалификатор означает, что структура есть типом-ссылкой;
  • квалификатор value. Этот квалификатор означает, что структура есть типом-значение.

2. Какое отличие между квалификаторами ref и value при работе со структурами?

Если объявить экземпляр (переменную) структуры с квалификатором ref ли value, то отличий нет. Доступ к элементам структур осуществляется через символ ‘ . ‘ (точка).

Отличие между квалификаторами ref и value проявляется в случаях:

  • если используются массивы структурных переменных (см. п.п. 5, 6);
  • если используются указатели на структуры.

При выделении памяти для указателя на структуру с модификатором ref эта структура размещается в управляемой (managed) куче (heap) и не может быть размещена в native-куче.

Если же выделить память для указателя на структуру с модификатором value, то структура может быть размещена и в managed-куче и в native-куче.

Подробно о работе указателей на managed-структуры описано в теме:

3. Как осуществляется работа со структурами ссылочного типа (ref)? Пример

В данном примере объявлена структура, которая описывает точку на координатной плоскости. Целесообразно размещать объявления шаблона структуры в отдельном «*.h» файле, например «MyStruct.h».

// структура MyPoint с квалификатором ref
ref struct MyPointR
{
    int x;
    int y;
};

Объявление переменной типа MyPoint и ее использование из другого программного кода (например, обработчика события клика на кнопке):

MyPointR mp;

mp.x = 23;
mp.y = 36;

 4. Как осуществляется работа со структурами типа «значение» (value)? Пример

Пример объявления шаблона value-структуры и ее экземпляра (переменной) в программе.

// шаблон структуры MyPoint с квалификатором value
value struct MyPointV
{
    int x;
    int y;
};

...

MyPointV mpv;
mpv.x = 334;
mpv.y = 43;

5. Пример использования массива структурных переменных с квалификатором ref. Массив ref-структур. Ключевое слово array

Если структура объявлена с квалификатором ref (ссылочного типа), то объявить массив структурных переменных в среде Visual C++/CLR стандартным для C/C++ способом не удастся. То есть, следующий код выдаст ошибку:

// ref-структуры - ссылочного типа
MyPointR MP[5]; // - ошибка!

Для объявления массива из ref-структур используется ключевое слово array. Далее продемонстрирована работа со структурой типа MyPoint (см. п. 4).

// ref-структуры - ссылочного типа
// MyPointR MP[5]; // - ошибка!
array <MyPointR ^> ^MP; // объявление массива ref-структур - только так

// array <MyPointR> MP2; - ошибка, должен быть символ ^

// выделение памяти для массива указателей на структуры
MP = gcnew array <MyPointR ^>(5);

// выделение памяти для каждого указателя
for (int i=0; i<5; i++)
    MP[i] = gcnew MyPointR;

// заполнение значениями массива
for (int i=0; i<5; i++)
{
    MP[i]->x = i*2;
    MP[i]->y = i*(i+1);
}

6. Пример использования массива структурных переменных с квалификатором value. Масив value-структур. Ключове слово array
// шаблон структуры MyPointV с квалификатором value
value struct MyPointV
{
    int x;
    int y;
};

// value-структуры - типа "значение"
array <MyPointV> ^MPV; // объявление массива

//array <MyPointV> MPV2; - так нельзя, ошибка. должен быть символ ^

// выделение памяти для 5 структур
MPV = gcnew array <MyPointV>(5);

// заполнение значениями
for (int i=0; i<5; i++)
{
    MPV[i].x = i*2;
    MPV[i].y = i*i;
}

7. Как представить строку в качестве поля в шаблоне структурной переменной?

Если структура объявлена с квалификатором ref или value, то объявить строку символов классическим способом

char s[10];

не удастся.

Для того, чтобы в шаблоне структурной переменной использовать строки символов, нужно использовать один из двух способов:

  • описать указатель на тип char;
  • описать массив типа char с использованием ключевого слова array. Затем выполнить соответствующее преобразование в тип, который удобно обрабатывать (например, String).

Пример. Пусть дан шаблон структуры, которая описывает координаты (x, y) точки на плоскости. Кроме того, каждая координата может иметь комментарий. В примере показаны два варианта представления строки символов (типа char). С целью демонстрации работы объявлены 2 переменные-указатели на char, которые имеют разные типы объявления указателей.

// структура MyPointR
ref struct MyPointR
{
    int x;
    int y;
    char * sx;         // указатель на тип char - строка символов
    array <char> ^sy; // использование ключевого слова array
};

Работа со структурой MyPointR продемонстрирована ниже.

MyPointR mpr;

mpr.x = 23;
mpr.y = 35;
mpr.sx = new char[10]; // это работает
mpr.sy = gcnew array <char>(10); // также работает

strcpy(mpr.sx, "X");

mpr.sy[0] = 'Y';
mpr.sy[1] = '\0';

// преобразование из массива array <char> в массив char[10]
char buffer[10]; // дополнительная переменная
for (int i=0; i<10; i++)
    buffer[i] = mpr.sy[i];

// преобразование из char[] в String для более удобного использования
String ^s = gcnew String(buffer);

8. Как в ref-структуре или value-структуре представить массив чисел? Примеры

В managed-структурах представить массив чисел классическим способом

int D[10];
double F[5][10];

не удастся.

Память для массивов нужно выделять динамично. Поэтому, для работы с массивами нужно описывать указатель на базовый тип. Более подробно о работе указателей описывается в темах:

Ниже приведены примеры организации работы с массивами, которые входят в ref-структуру и value-структуру.

Пример 1. Представление массива из n целых чисел в ref-структуре.

// Шаблон ref-структуры, в которой реализована массив из з n целых чисел
// двумя способами
ref struct IntArrayR
{
    int n; // количество чисел в массиве
    int * A1; // неуправляемый указатель на массив int-чисел
    array <int> ^A2; // managed-указатель на массив int-чисел
};

Использование шаблона структуры IntArrayR

// Шаблон ref-структуры IntArrayR
IntArrayR mA; // mA - структурная переменная

// в массиве должно быть 5 чисел
mA.n = 5;

// выделение памяти для массива чисел int,
// на который указывает неуправляемый (*) указатель
mA.A1 = new int[mA.n];

// выделение памяти для массива
mA.A2 = gcnew array <int>(mA.n);

// заполнение массивов A1 и A2 значениями
for (int i=0; i<mA.n; i++)
{
    mA.A1[i] = i*3+5;
    mA.A2[i] = i*i-2;
}

// отображение массивов в listBox1 и listBox2
listBox1->Items->Clear();
listBox2->Items->Clear();
for (int i=0; i<mA.n; i++)
{
    listBox1->Items->Add(mA.A1[i].ToString());
    listBox2->Items->Add(mA.A2[i].ToString());
}

Пример 2. Представление массива из n вещественных чисел в value-структуре. Нахождение суммы элементов массива.

// Шаблон value-структуры, реализующей массив из n вещественных чисел
value struct FloatArrayV
{
    float n;   // количество чисел в массиве
    float * A1; // неуправляемый указатель на массив float-чисел
    array <float> ^A2; // managed-указатель на массив float-чисел
};

Робота со структурой FloatArrayV:

// Использование value-структуры FloatArrayV
FloatArrayV fA;

// в структуре массив из 10 чисел
fA.n = 10;

fA.A1 = new float[fA.n]; // выделение памяти для одномерного массива A1
fA.A2 = gcnew array <float>(10); // выделение памяти для массива A2

// заполнение значений массивов
for (int i=0; i<fA.n; i++)
{
    fA.A1[i] = System::Math::Sin(i) + System::Math::Cos(i);
    fA.A2[i] = i*System::Math::Sqrt(i);
}

// Нахождение сумм элементов массивов
float sum1 = 0, sum2 = 0;
for (int i=0; i<fA.n; i++)
{
    sum1 += fA.A1[i];
    sum2 += fA.A2[i];
}

label1->Text = "sum(A1) = " + sum1.ToString();
label2->Text = "sum(A2) = " + sum2.ToString();

9. Как осуществляется присвоение managed-структур? Пример

Присваивать можно только структуры-значение, то есть структуры, которые объявлены с квалификатором value. В этом случае происходит копирование данных (значений полей) с одной структуры в другую.

Поскольку, структуры с квалификатором ref есть структурами-ссылками, то присваивать их нельзя.

Пример. Присвоение value-структур.

// Присвоение value-структур
MyPoint_value mpv;

mpv.x = 300;
mpv.y = 500;
mpv.color = 5;

MyPoint_value mpv2;

mpv2 = mpv; // присвоение структур

int d;
d = mpv2.x; // d = 300

10. Как осуществляется инициализация managed-структур? Пример

Для managed-структур инициализацию можно делать только для структур-значений или value-структур. Для структур-ссылок, объявление которых начинается со слова ref, инициализацию сделать не удастся.

Пример 1. Инициализация структуры с квалификатором value. Пусть задан шаблон структуры, которая описывает точку на экране монитора.

// структура объявлена с квалификатором value
value struct MyPoint_value
{
    int x;
    int y;
    int color;
};

Тогда инициализация переменной (экземпляра) структуры будет следующая:

// инициализация value-структуры
MyPoint_value mpv = { 3, 4, 5 };

Пример 2. Пусть задан шаблон Book, описывающий книгу в библиотеке.

value struct BookV
{
    char * title;
    char * author;
    int year;
    float price;
};

Инициализация структурной переменной будет следующая:

// инициализация value-структуры
BookV bv1 = { NULL, NULL, 2002, 23.55 };
BookV bv2 = { "Title-1", "Author-1", 2000, 30.44 };

String ^s = gcnew String(bv2.title); // s = "Title-1"

11. Пример объявления и использования массива ref-структур внутри ref-структуры

Как известно, объявить массив native-структур и value-структур в ref-структуре не удастся. В ref-структуре можно объявлять только массив ref-структур.

Пусть задан шаблон ref-структуры, которая описывает точку на плоскости, которая имеет цвет.

// структура объявлена с квалификатором ref
ref struct MyPoint_ref
{
    int x;
    int y;
    int color;
};

Если нужно объявить массив точек MyPoint_ref в структуре, тогда надо написать следующий код

// шаблон структуры, в которой есть массив точек (структур)
ref struct PointsArray_ref
{
    int n; // количество точек
    array <MyPoint_ref ^> ^mp;
};

В программе (другом программном коде) можна использовать шаблон Points_Array_ref приблизительно следующим образом

// Указатель на структуру PointsArray_ref
PointsArray_ref ^pA;
pA = gcnew PointsArray_ref; // выделение памяти

pA->n = 5;

// выделение памяти для указателей на MyPoint_ref
pA->mp = gcnew array <MyPoint_ref ^>(pA->n);

// выделение памяти для элементов массива внутри структуры
for (int i=0; i<pA->n; i++)
{
    pA->mp[i] = gcnew MyPoint_ref;
}

// заполнение структур значениями
for (int i=0; i<pA->n; i++)
{
    pA->mp[i]->x = i*5+2;
    pA->mp[i]->y = i*i+3;
    pA->mp[i]->color = i;
}

// небольшая проверочка
int d;
d = pA->mp[3]->x; // d = 3*5+2 = 17
d = pA->mp[4]->y; // d = 4*4+3 = 19

12. Пример объявления и использования массива value-структур внутри value-структуры

Задан шаблон структуры MyPoint_value, описывающий точку з цветом на плоскости.

// структура объявлена с квалификатором value
value struct MyPoint_value
{
    int x;
    int y;
    int color;
};

Задан шаблон структуры PointsArray_value, содержащий массив точек (структур MyPoint_value).

// массив value-структур в структуре
value struct PointsArray_value
{
    int n; // количество точок
    array <MyPoint_value> ^mp;
};

Демонстрация использования структуры PointsArray_value.

// массив value-структур в структуре
PointsArray_value mA;

mA.n = 5;

// выделение памяти для массива
mA.mp = gcnew array <MyPoint_value>(mA.n);

// заполнение элементов структур значениями
for (int i=0; i<mA.n; i++)
{
    mA.mp[i].x = i*5+2;
    mA.mp[i].y = i*i+5;
    mA.mp[i].color = i;
};

// проверка
int d;
d = mA.mp[3].x; // d = 17

13. Пример объявления и работы с двумерным массивом ref-структур

 Задана ref-структура, описывающая точку на плоскости

ref struct MyPoint_ref
{
    int x;
    int y;
    int color;
};

Демонстрация работы с двумерным массивом ref-структур размером 5*10

// Двумерный массив ref-структур. Этапы работы
// 1. Объявление переменной с именем типа 'двумерный массив ref-структур'
array <MyPoint_ref ^, 2> ^mp;

// 2. Выделение памяти для указателей на структуры в массиве размером 5*10
mp = gcnew array <MyPoint_ref ^,2>(5, 10);

// 3. Выделение памяти для элементов массива - ref-структур MyPoint_ref
for (int i=0; i<5; i++)
    for (int j=0; j<10; j++)
        mp[i,j] = gcnew MyPoint_ref;

// 4. Заполнение произвольными значениями структур
for (int i=0; i<5; i++)
    for (int j=0; j<10; j++)
    {
        mp[i,j]->x = i + j*3;
        mp[i,j]->y = i*i + j;
        mp[i,j]->color = i + j;
    }

// 5. Проверка
int d;
d = mp[2,4]->x; // d = 2+4*3 = 14
d = mp[0,3]->y; // d = 0*0+3 = 3
d = mp[3,8]->color; // d = 3+8 = 11

 

 14. Пример объявления и работы с двумерным массивом value-структур

Пусть задан шаблон value-структуры

value struct MyPoint_value
{
    int x;
    int y;
    int color;
};

Тогда работа с двумерным массивом таких структур размером 5*10 будет приблизительно следующей:

// Двумерный массив value-структур. Этапы работы
// 1. Объявление переменной mp типа 'двумерный value-массив MyPoint_value'
array <MyPoint_value, 2> ^mp;

// 2. Выделение памяти для двумерного массива
mp = gcnew array <MyPoint_value, 2>(5, 10);

// 3. Заполнение значениями полей массива
for (int i=0; i<5; i++)
    for (int j=0; j<10; j++)
    {
        mp[i,j].x = i*i + j;
        mp[i,j].y = i*5 - j;
        mp[i,j].color = i + j*2;
    }

// 4. Проверка
int d;
d = mp[2,3].x; // d = 7
d = mp[3,0].color; // d = 3
d = mp[1,2].y; // d = 3

 


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