![]() | Лабораторна робота №2 Визначення типів об'єктів, використовуючи динамічну ідентифікацію типів. RTTI Мета: Засвоєння поняття динамічної ідентифікації типів та способів ідентифікації типів об'єктів на етапі виконання. Набуття практичних прийомів ідентифікації типів. У деяких випадках дуже важливо знати точний тип об'єкта. Наприклад, ім'я класу об'єкта або спосіб його розміщення в пам'яті. Для цієї мети служить оператор Typeid. Динамічна ідентифікація типу дає можливість визначити тип об'єкта під час виконання програми. Нові оператори приведення типів надають більш безпечні і керовані способи виконання операцій приведення типів, в порівнянні з існуючими раніше. В С ++ поліморфізм реалізується через ієрархії класів, віртуальні функції і вказівники базових класів. При такому підході вказівник базового класу може використовуватися або для вказівки на об'єкт базового класу, або для вказівки на об'єкт будь-якого класу, похідного від цього базового. Отже, не завжди є можливість заздалегідь дізнатися тип об'єкта, на який буде вказувати покажчик базового класу в кожен даний момент часу. У таких випадках визначення типу об'єкта повинно відбуватися під час виконання програми, а для цього служить механізм динамічної ідентифікації типу. Інформацію про тип об'єкта отримують за допомогою оператора typeid. Для використання оператора typeid в програму слід включити заголовок <typeinfo>. Нижче представлена основна форма оператора typeid: typeid(об’єкт) Тут об'єкт - це той об'єкт, інформацію про тип якого необхідно отримати. Оператор typeid повертає посилання на об'єкт типу type_info, який і визначає тип об'єкта об'єкт. У класі type_info визначені наступні відкриті члени: bool operator==(const typeinfo &об’єкт); bool operator!=(const typeinfo &об’єкт); bool before(const typeinfo &об’єкт); const char *name(); Порівняння типів забезпечують перевантажені оператори == та ! =. Функція before () повертає істину, якщо викликає об'єкт в порядку сортування розташований раніше об'єкта заданого в якості параметра. (Ця функція зазвичай призначена тільки для внутрішнього використання. Її значення, що повертається навряд чи може стати в нагоді при операціях з успадкуванням або ієрархіями класів.) Функція name () повертає покажчик на ім'я типу. Хоча оператор typeid дозволяє отримувати типи різних об'єктів, найбільш корисний він буде, якщо в якості його аргументу задати покажчик поліморфного базового класу. У цьому випадку оператор автоматично повертає тип реального об'єкта, на який вказує покажчик. Цим об'єктом може бути як об'єкт базового класу, так і об'єкт будь-якого класу, похідного від цього базового. (Згадайте, покажчик базового класу може вказувати або на об'єкт базового класу, або на об'єкт будь-якого класу, похідного від цього базового.) Таким чином, за допомогою оператора typeid вказано посилання на об'єкт поліморфного класу, оператор повертає тип реального об'єкта, на який є посилання . Цим об'єктом, так само як і у випадку з покажчиком, може бути об'єкт похідного класу. Коли оператор typeid застосовують до не поліморфного класу, отримують покажчик або посилання базового типу. Нижче представлена друга форма оператора typeid, в який в якості аргументу вказують ім'я типу: typeid (ім'ятипу) Зазвичай за допомогою даної форми оператора typeid отримують об'єкт типу type_info, який можна використовувати в інструкції порівняння типів. Оскільки оператор typeid найчастіше застосовують до розмінованого вказівника (тобто до вказівника, до якого вже був застосований оператор *). Для обробки положення, коли розмінований покажчик дорівнює нулю, була придумана спеціальна виняткова ситуація bad_typeid, яку в цьому випадку збуджує оператор typeid. Динамічна ідентифікація типу використовується далеко не в кожній програмі. Проте, якщо ви працюєте з поліморфними типами даних, вона дозволяє в найрізноманітніших ситуаціях визначати типи оброблюваних об'єктів. У наступній програмі демонструється використання оператора typeid. Спочатку за допомогою цього оператора ми отримуємо інформацію про один з вбудованих типів даних C ++ - типі int. Потім оператор typeid дає нам можливість вивести на екран типи об'єктів, на які вказує вказівник p, що є вказівником базового класу BaseClass. #include #include { public: virtual void f() {}; // класс BaseClass стає поліморфним }; class Derivedl: public BaseClass { public: virtual void f() {}; // поширюється поліморфізм }; class Derived2: public BaseClass { public: virtual void f() {}; // поширюється поліморфізм }; int main() { int i; BaseClass *p, baseob; Derivedl ob1; Derived2 ob2; // Вивід на екран інформації про вбудований тип cout << "Типом змінної i є "; cout << typeid(i).name() << endl; // Реалізація поліморфізму р = &baseob; cout << "Вказівник р вказує на об’єкт типу ”; cout << typeid (*p).name() << endl; р = &ob1; cout << "Вказівник р вказує на об’єкт типу ”; cout << typeid(*p).name() << endl; р = &ob2; cout << "Вказівник р вказує на об’єкт типу ”; cout << typeid(*p).name ()<<endl; return 0; } Програма виводить на екран наступну інформацію: Тип змінної i є int Вказівник p вказує на об'єкт типу BaseClass Вказівник p вказує на об'єкт типу Derivedl Вказівник p вказує на об'єкт типу Derived2 Коли аргументом оператора typeid передається вказівник на поліморфний батьківський клас, то реальний тип об’єкта на який посилається вказівник, буде визначатись під час виконання програми. З іншого боку, якщо аргументом оператору typeid передається посилання на поліморфний батьківський клас, то типом, який повернеться оператором typeid, буде тип реального об’єкта, на який оголошено посилання. В наступному прикладі в оголошенні функції WhatType() об’єкт типу BaseClass буде заданий параметром-посиланням. Це означає, що функції WhatType() можна передавати посилання на об’єкти типу BaseClass або типів, які є похідними від цього класу. Якщо оператору typeid передати такий аргумент, то він поверне тип реального об’єкта // Задання посилання параметром функції void WhatType (BaseClass &ob) { cout << "ob - це посилання на об’єкт типу "; cout < } int main ( ) { int i ; BaseClass baseob; Derivedl ob1; Derived2 ob2; WhatType(baseob); WhatType(ob1); WhatType(ob2); return 0; } Програма виводить на екран наступну інформацію: ob - це посилання на об'єкт типу BaseClass ob - це посилання на об'єкт типу Derivedl ob - це посилання на об'єкт типу Derived2 Якщо необхідно дізнатися, чи відповідають один одному типи декількох об'єктів. Це легко зробити, знаючи, що об'єкт типу type_info, що повертається оператором typeid, перевантажує оператори == і! =. У представленій нижче програмі показано використання цих операторів. // Використання операторів == і != З оператором typeid #include #include { virtual void f () {} }; class Y { virtual void f () {} }; int main () { X xl, x2; Y yl; if (typeid(xl) == (typeid(x2)) cout << "Тип об'єктів xl і x2 однаковий \n"; else cout << "Тип об'єктів xl і x2 не однаковий \n"; if (typeid(xl)!= (typeid(yl)) cout << "Тип об'єктів xl і yl не однаковий \n"; else cout << "Тип об'єктів xl і yl однаковий \n"; return 0; } Програма виводить на екран наступну інформацію: Тип об'єктів xl і х2 однаковий тип об'єктів xl і yl не однаковий Приклад застосування typeid::name() для поліморфних типів Shape *s[3]; s[0] = new Circle(10); s[1] = new Rectangle(1, 8); s[2] = new Triangle(5, 12, 7); // Визначаємо тип елеменов масиву for (int i = 0; i < 3; i++) puts(typeid(*s[i]).name()); Завдання до лабораторної роботи У програмі повинна бути визначена проста ієрархія класів, призначених для малювання на екрані початкових букв прізвища, ім'я, по батькові (LastName, FirstName, MiddleName) та NullShape у якому немає якої б то не було форми. NullShape не може бути на вершині ієрархії. Функція generator () повинна генерувати об'єкт і повертати покажчик на нього. Те, який саме об'єкт створюється, повинно визначатись випадково. Використовуючи динамічну ідентифікацію у функції main () реалізувати вивід об'єктів різних типів на екран, виключаючи об'єкти типу NullShape (у випадку генерування NullShape має спрацювати лише динамічна індикація). Контрольні питання 1. Що представляє система RTTI (Runtime Type Identification)? 2. Коли потрібно використовувати RTTI? 3. Як визначити тип об’єкта? 4. Що потрібно для отримання структури type_info? 5. Які операції та методи підтримує структура type_info? 6. Опишіть зміст оператора typeid. 7. Як відбувається порівняння типів? |