Структури. Частина 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”.
// структура MyPointR з кваліфікатором ref ref struct MyPointR { int x; int y; };
Оголошення змінної типу MyPointR та її використання з іншого програмного коду (наприклад, обробника події кліку на кнопці):
MyPointR mp; mp.x = 23; mp.y = 36;
4. Як здійснюється робота зі структурами типу “значення” (value)? Приклад
Приклад оголошення шаблону value-структури та її екземпляру (змінної) в програмі.
// шаблон структури MyPointV з кваліфікатором 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. Нижче продемонстровано роботу з структурою типу MyPointR (див. п. 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. Нехай задано шаблон BookV, що описує книгу в бібліотеці.
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; };
У програмі (іншому програмному коді) можна використати шаблон PointsArray_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;
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. Двовимірні масиви. Масиви рядків. Багатовимірні масиви
- Покажчики. Частина 1. Загальні поняття. Типи покажчиків. Керовані та некеровані покажчики. Покажчик на функцію. Приклади використання
- Покажчики. Частина 2. Некеровані покажчики. Операції над покажчиками. Покажчик на тип void. Виділення пам’яті. Нульовий покажчик. Операція взяття адреси &