Структуры. Часть 3. Работа с managed-структурами в среде CLR. Квалификаторы ref и value. Объявление структурных переменных. Массивы managed-структурных переменных. Инициализация managed-структур
Эта тема базируется на теме:
Содержание
- 1. Какие квалификаторы используются с managed-структурами в среде CLR?
- 2. Какое отличие между квалификаторами ref и value при работе со структурами?
- 3. Как осуществляется работа со структурами ссылочного типа (ref)? Пример
- 4. Как осуществляется работа со структурами типа «значение» (value)? Пример
- 5. Пример использования массива структурных переменных с квалификатором ref. Массив ref-структур. Ключевое слово array
- 6. Пример использования массива структурных переменных с квалификатором value. Масив value-структур. Ключове слово array
- 7. Как представить строку в качестве поля в шаблоне структурной переменной?
- 8. Как в ref-структуре или value-структуре представить массив чисел? Примеры
- 9. Как осуществляется присвоение managed-структур? Пример
- 10. Как осуществляется инициализация managed-структур? Пример
- 11. Пример объявления и использования массива ref-структур внутри ref-структуры
- 12. Пример объявления и использования массива value-структур внутри value-структуры
- 13. Пример объявления и работы с двумерным массивом ref-структур
- 14. Пример объявления и работы с двумерным массивом value-структур
- Связанные темы
Поиск на других ресурсах:
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];
не удастся.
Память для массивов нужно выделять динамично. Поэтому, для работы с массивами нужно описывать указатель на базовый тип. Более подробно о работе указателей описывается в темах:
- Указатели. Часть 1. Общие понятия. Типы указателей. Управляемые и неуправляемые указатели. Указатель на функцию. Примеры использования
- Указатели. Часть 2. Неуправляемые указатели. Операции над указателями. Указатель на тип void. Выделение памяти. Нулевой указатель. Операция взятия адреса &
- Указатели. Часть 3. Неуправляемые указатели и массивы. Указатель на структуру. Указатель на класс
Ниже приведены примеры организации работы с массивами, которые входят в 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
Связанные темы
- Структуры. Часть 1. Составные типы данных. Шаблон структуры. Структурная переменная. Структуры в среде CLR. Объявление и инициализация структурной переменной
- Структуры. Часть 2. Выделение памяти для структуры. Вложенные структуры. Массивы native-структур
- Структуры. Часть 4. Структуры и функции. Передача структуры в функцию в среде CLR. Возврат структуры из функции
- Массивы. Часть 1. Определение массива. Одномерные массивы. Инициализация массива
- Массивы. Часть 2. Двумерные массивы. Массивы строк. Многомерные массивы