Динамическая идентификация типов. Операторы 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
⇑
Связанные темы
⇑