..1 Механізм RTTI (run-time type identification)
..1.1 static_cast і покажчики
Неявне приведення покажчика на об'єкт похідного типу до покажчика на об'єкт базового типу компілятор прекрасно виконує сам, так як похідний клас містить повні визначення своїх базових класів => таке підвищує (upcast) приведення типу завжди безпечно!
Вірно і наступне твердження: якщо об'єкт насправді є об'єктом похідного типу, а в нашому розпорядженні є покажчик на базовий клас, то коректним повинно бути і перетворення покажчика "вниз" по ієрархії класів аж до перетворення такого покажчика до покажчика на фактичний (цільової) тип - знижує приведення (downcast).
Для приведення покажчика на базовий тип до покажчика похідного типу призначений оператор явного приведення типу static_cast - це механізм часу компіляції!
// A і b пов'язані спадкуванням
class B: public A
// З - «автономний» клас
B * pB = static_cast(PA); // з точки зору компілятора все коректно, так як класи пов'язані спадкуванням!
// F (d); // помилка компілятора - такого перетворення немає!
F (a); // помилки компілятора немає, але результат некоректний, оскільки насправді об'єкт A, а не B!
Зауваження: компілятор перевіряє тільки той факт, що обидва класи пов'язані з допомогою наслідування => вважає таке приведення коректним. А насправді таке перетворення небезпечно! Тому виникла необхідність в способі перевірки можливості такого перетворення.
Зауваження: static_cast зазвичай використовується для неполіморфних типів (немає віртуальних функцій).
..1.2 Динамічна ідентифікація типу
RTTI характеризується трьома поняттями:
1) оператор dynamic_cast - для перетворення поліморфних типів
2) оператор typeid - для визначення точного (exact) типу об'єкта
3) клас type_info - (це те, що повертає оператор typeid)
..1.3 Для підключення RTTI:
1) в опціях проекту Project \ Properties \ C / C ++ \ Language - включити Enable Run-Time Type info (або / GR)
2) #include
3) механізм працює тільки для поліморфних класів (тобто задіяні таблиці віртуальних функцій)
..1.4 Оператор typeid і клас type_info Мейерс2 - стр132
Ідентифікація типів під час виконання дозволяє отримати інформацію про об'єкти і класах. При цьому для зберігання інформації, яка запитується повинна бути відведена область пам'яті.
1) скільки б об'єктів класу X ми не створювали, досить зберігати інформацію власне про тип X в єдиному екземплярі в кожному класі => для кожного класу компілятор створює структуру даних типу type_info
2) повинен існувати спосіб отримання цієї інформації для кожного об'єкта => доступ до об'єкта type_info можна отримати за допомогою оператора typeid.
3) Що існує в єдиному екземплярі для всіх об'єктів? - static або таблиця віртуальних функцій. У специфікації мови сказано, що отримання цієї інформації гарантується тільки для поліморфних типів (тобто якщо є хоча б одна віртуальна функція). Дані RTTI виконують приблизно ту ж задачу, що і таблиця віртуальних функцій => RTTI була розроблена саме за допомогою віртуальної таблиці класу. Наприклад індекс 0 у таблиці може містити покажчик на об'єкт type_info:
При такій реалізації пам'ять буде витрачатися тільки на додавання ще одного осередку в кожну таблицю віртуальних функцій + виділення пам'яті для зберігання об'єкта type_info для кожного класу.
..1.4.1 Формат type_info
int operator == (const type_info rhs) const;
int operator! = (const type_info rhs) const;
int before (const type_info rhs) const;
const char * raw_name () const; // декорірованноеімя
Основні можливості: 1) перевантажені оператори == і! =.
2) + методи для отримання імені класу.
..1.4.2 Форми оператора typeid:
const type_info typeid (об'єкт) // де в якості об'єкта може виступати вираз, наприклад (* P)
const type_info typeid (тип)