Динамічна ідентифікація типів. Оператори dynamic_cast, const_cast, reinterpret_cast, static_cast. Приклади
Зміст
- 1. Оператор dynamic_cast. Приклад
- 2. Заміна оператора typeid оператором dynamic_cast
- 3. Оператор const_cast. Приклад
- 4. Оператор reinterpret_cast. Приклад
- 5. Оператор static_cast. Приклад
- Споріднені теми
Пошук на інших ресурсах:
1. Оператор dynamic_cast. Приклад
Оператор dynamic_cast використовується для динамічного приведення типу з одночасною перевіркою коректності приведення. Якщо приведення не може бути виконане, то воно не виконується і оператор повертає нульове значення (nullptr).
Загальна форма оператора dynamic_cast наступна
dynamic_cast<type> (expression);
тут
- type – результуючий тип;
- expression – вираз, що приводиться до типу type.
Оператор dynamic_cast є ефективним у випадку приведення типів, що утворюють ієрархію успадкування (полімофних типів).
Якщо оператор dynamic_cast застосовується до покажчиків, то повертається нульовий покажчик (nullptr). Якщо цей оператор застосовується до посилань, то у випадку помилки генерується виключна ситуація bad_cast.
Приклад.
У прикладі демонструється використання оператора dynamic_cast для двох класів A та B, які утворюють ієархію успадкування. Розглядаються різноманітні можливі ситуації використання оператора.
#include <iostream> #include <typeinfo> using namespace std; // Оператор dynamic_cast<> - визначає, чи можна динамічно привести типи. // Базовий клас class A { public: virtual void Show() { cout << "A::Show()" << endl; } }; // Похідний клас class B :public A { public: void Show() { cout << "B::Show()" << endl; } }; void main(void) { // 1. Оголосити змінні A* pA; // покажчик на базовий клас B* pB; // покажчик на похідний клас A a; B b; // 2. Використати покажчик pA pA = &a; // Так можна pA->Show(); // Також можна, покажчик на базовий клас може вказувати на // екземпляр похідного класу. pA = &b; pA->Show(); // 3. Використати покажчик pB // Так не можна // pB = &a; // заборонено, базовий клас не може розширитись до похідного // 4. Використання оператора dynamic_cast. // Випадок: покажчик отримує адресу екземпляру класу cout << "dynamic_cast<type*>(&obj): " << endl; // 4.1. Приведення B* <= A* з перевіркою pB = dynamic_cast<B*> (&a); // не можна, pB = nullptr if (pB==nullptr) cout << "Cast A* <= B* -> Error" << endl; // цей варіант else cout << "Cast A* <= B* -> Ok" << endl; // 4.2. Приведення B* <= B* pB = dynamic_cast<B*> (&b); // можна if (pB != nullptr) cout << "Cast B* <= B* -> Ok" << endl; // цей варіант else cout << "Cast B* <= B* -> Error" << endl; // 4.3. Приведення A* <= A* pA = dynamic_cast<A*>(&a); // можна, pA!=nullptr if (pA != nullptr) cout << "Cast A* <= A* -> Ok" << endl; else cout << "Cast A* <= A* -> Error"; // 4.4. Приведення A* <= B* pA = dynamic_cast<B*>(&b); // можна if (pA) cout << "Cast A* <= B* -> Ok" << endl; else cout << "Cast A* <= B* -> Error"; cout << "---------------------------------" << endl; // 5. Використання оператора dynamic_cast. // Випадок: покажчик отримує адресу іншого покажчика cout << "dynamic_cast<type*>(ptr -> Type): " << endl; // 5.1. Приведення B* <= B* // Покажчик pA посилається на об'єкт класу B pA = &b; // можна, pA->b pB = dynamic_cast<B*>(pA); // можна, тому що pA посилається на об'єкт класу B if (pB) cout << "Cast B* <= (pA -> B) --> Ok " << endl; // + else cout << "Cast B* <= (pA -> B) --> Error " << endl; // 5.2. Приведення B* <= A* // Покажчик pA посилається на об'єкт класу A pA = &a; // pA -> A pB = dynamic_cast<B*>(pA); // неможна, тому що pA посилається на об'єкт класу A if (pB) cout << "Cast B* <= (pA -> A) --> Ok " << endl; else cout << "Cast B* <= (pA -> A) --> Error " << endl; // + // 5.3. Приведення A* <= B* // Покажчик pB вказує на об'єкт класу B pB = &b; pA = dynamic_cast<A*> (pB); // можна if (pA) cout << "Cast A* <= (pB -> B) --> Ok " << endl; else cout << "Cast A* <= (pB -> B) --> Error" << endl; // 5.4. Приведення A* <= A* // pB = &a; // помилка компіляції }
Результат виконання програми
A::Show() B::Show() dynamic_cast<type*>(&obj): Cast A* <= B* -> Error Cast B* <= B* -> Ok Cast A* <= A* -> Ok Cast A* <= B* -> Ok --------------------------------- dynamic_cast<type*>(ptr -> Type): Cast B* <= (pA -> B) --> Ok Cast B* <= (pA -> A) --> Error Cast A* <= (pB -> B) --> Ok
⇑
2. Заміна оператора typeid оператором dynamic_cast
Якщо класи утворюють ієрархію (класи є поліморфними), то оператор typeid може бути замінений оператором dynamic_cast.
У прикладі нижче демонструється ця можливість.
#include <iostream> #include <typeinfo> using namespace std; // заміна оператора typeid оператором dynamic_cast class A { public: virtual void Show() { cout << "A::Show()" << endl; } }; class B :public A { public: void Show() { cout << "B::Show()" << endl; } }; void main(void) { // 1. Оголошення покажчиків та об'єктів класів A* pA; // покажчик на базовий клас B* pB; // покажчик на похідний клас A a; B b; // 2. Застосування оператора typeid cout << "typeid:" << endl; // 2.1. pA->A pA = &a; if (typeid(*pA) == typeid(B)) // чи можна *pA привести до типу B { pB = (B*)pA; cout << "Cast B <= (pA->A) --> OK" << endl; } else cout << "Cast B <= (pA->A) --> Error" << endl; // 2.2. pA->B pA = &b; if (typeid(*pA) == typeid(B)) // чи можна *pA привести до типу B { pB = (B*)pA; cout << "Cast B <= (pA->B) --> OK" << endl; } else cout << "Cast B <= (pA->B) --> Error" << endl; // 3. Застосування оператора dynamic_cast cout << "-----------------------------------" << endl; cout << "dynamic_cast: " << endl; // 3.1. pA->A pA = &a; pB = dynamic_cast<B*> (pA); if (pB) cout << "Cast B* <= (pA->A) --> OK" << endl; else cout << "Cast B* <= (pA->A) --> Error" << endl; // 3.2. pA->B pA = &b; pB = dynamic_cast<B*> (pA); if (pB) cout << "Cast B* <= (pA->B) --> OK" << endl; else cout << "Cast B* <= (pA->Error) --> Error" << endl; }
Результат виконання програми
typeid: Cast B <= (pA->A) --> Error Cast B <= (pA->B) --> OK ----------------------------------- dynamic_cast: Cast B* <= (pA->A) --> Error Cast B* <= (pA->B) --> OK
⇑
3. Оператор const_cast. Приклад
Оператор const_cast використовується, щоб замінити модифікатор const і/або модифікатор volatile.
В цьому операторі тип результату повинен співпадати з вихідним. Оператор const_cast застосовується, щоб позбутися модифікатора const.
Загальний вигляд оператора const_cast наступний
const_cast<type> (expr)
Приклад.
З допомогою оператора const_cast через посилання на константну величину можна зняти модифікатор const з цієї константної величини.
#include <iostream> using namespace std; // 1. Застосування const_cast для посилання void ExampleConstCast1(const int& value) { // зняти специфікатор const, отримати доступ до value int& ref = const_cast<int&> (value); ref = 20; // через посилання на константну величину можна доступитись до value // value = 50; - неможна, expression must be a modifiable lvalue } // 2. Застосування const_cast для посилання void ExampleConstCast2(const int& value) { // зняти модифікатор const з value const_cast<int&> (value) = value + value; } // 3. Застосування const_cast для покажчика void ExampleConstCast3(const int* x) { int* p = const_cast<int*> (x); // зняти const з x *p = 100; } void main() { // Демонстрація використання модифікатора const_cast int t = 30; ExampleConstCast1(t); cout << "t = " << t << endl; // t = 20 ExampleConstCast2(t); cout << "t+t = " << t << endl; // t = 20+20 = 40 int x = 50; ExampleConstCast3(&x); cout << "x = " << x << endl; // x = 100 }
Результат виконання програми
t = 20 t+t = 40 x = 100
⇑
4. Оператор reinterpret_cast. Приклад
Оператор reinterpret_cast призначений для перетворення одного типу в інший, навіть не сумісний тип. Цей оператор може також застосовуватись і до покажчиків будь-яких типів.
Загальна форма
reinterpret_cast<type> (expr)
де
- type – результуючий тип;
- expr – вираз, що приводиться до нового типу.
Приклад.
#include <iostream> using namespace std; void main() { // 1. Конвертувати char* => int int number; const char* pStr = "Hello world!"; // отримати покажчик на str як ціле число number = reinterpret_cast<int> (pStr); cout << "number = " << number << endl; // 2. Конвертувати int => double*, // перетворити ціле число в покажчик unsigned int num = 300; double* p; p = reinterpret_cast<double*> (num); cout << "p = " << p << endl; }
Результат виконання програми
number = 9476928 p = 0000012C
⇑
5. Оператор static_cast. Приклад
Оператор static_cast використовується для виконання неполіморфного приведення типів без перевірки його коректності. Тип, що приводиться, та тип, що отримується, можуть бути такими, що не утворюють ієрархію успадкування.
Загальна форма оператора наступна
static_cast<type> (expr)
тут
- type – результуючий тип;
- expr – вираз, який приводиться до типу type.
Приклад.
#include <iostream> using namespace std; void main() { // Застосування оператора static_cast - неполіморфне приведення, // використовуєтсья так само як і звичайний оператор приведення // 1. Конвертування int => double double x; int a = 25; x = static_cast<double> (a) / 4; cout << "x = " << x << endl; // x = 6.25 // 2. Конвертування double => char double z = 51.55; char c = static_cast<char> (z); // c = '3' cout << "c = " << c << endl; // 3. Конвертування double => short short s = static_cast<short>(118.232); cout << "s = " << s << endl; // s = 118 }
Результат виконання програми
x = 6.25 c = 3 s = 118
⇑
Споріднені теми
⇑