Студопедия КАТЕГОРИИ: АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Преобразование полиморфных типов dynamic_cast
Материал этого подраздела взят из MSDN 2005. Формат операции: dynamic_cast <type_id> (exp)
Преобразует выражение exp в объект указанного типа type_id. Идентификатор type_id должен быть указателем или ссылкой на прежде определенный тип класс или нетипизированным указателем (void *). Тип выражения exp должен быть указателем, если type_id является указателем, или левосторонним выражением, если type_id является ссылкой. Если type_id является указателем на непосредственный базовый класс или на непрямой базовый класс, результатом приведения типа является указатель типа type_id. Пример: // dynamic_cast_1.cpp // compile with: /c class B { }; class C : public B { }; class D : public C { };
void f(D* pd) { C* pc = dynamic_cast<C*>(pd); /* корректно: C является непосредственным родительским классом и pc указывает на объект типа C */ B* pb = dynamic_cast<B*>(pd); /* тоже корректно: C является непрямым родительским классом и pb указывает на объект типа B */ }
Этот тип преобразования называется "upcast", поскольку он перемещает указатель вверх по иерархии классов от производного класса к родительскому. Такое преобразование является неявным (implicit) преобразованием. Если type_id является нетипизированным указателем void*, проверка действительного типа выражения производится на этапе выполнения программы. Результатом является указатель на объект, определяемый выражением, например: // dynamic_cast_2.cpp // compile with: /c /GR class A {virtual void f();}; class B {virtual void f();};
void f() { A* pa = new A; B* pb = new B; void* pv = dynamic_cast<void*>(pa); // pv теперь указывает на объект типа A pv = dynamic_cast<void*>(pb); // pv теперь указывает на объект типа B }
Если type_id не void*, осуществляется проверка на этапе выполнения того, что объект, определяемый выражением exp, может быть преобразован к типу type_id. Если тип выражения является базовым классом для типа type_id, осуществляется проверка (на этапе выполнения) того, что выражение exp действительно указывает на объект типа type_id. Если это так, то указатель будет указывать на объект типа type_id, например: // dynamic_cast_3.cpp // compile with: /c /GR class B {virtual void f();}; class D : public B {virtual void f();};
void f() { B* pb = new D; // непрозрачно, но допустимо B* pb2 = new B;
D* pd = dynamic_cast<D*>(pb); // корректно, pb действительно указывает на D D* pd2 = dynamic_cast<D*>(pb2); // pb2 указывает не на D, а на B }
Этот тип преобразования называется "downcast" потому, что он перемещает указатель вниз по иерархии классов, от родительского класса к производному, т.е. наследуемому.
Если в операции dynamic_cast < type-id > (exp)
выражение exp не может быть безопасно конвертировано в тип type_id, контроль на этапе выполнения вызывает ошибку, например: // dynamic_cast_7.cpp // compile with: /c /GR class A {virtual void f();}; class B {virtual void f();};
void f() { A* pa = new A; B* pb = dynamic_cast<B*>(pa); // вызывает ошибку, т.к. небезопасно }
Если приведение типа не состоялось по ошибке, то указатель будет иметь нулевое значение. Неудавшееся приведение типа вызывает исключительную ситуацию bad_cast. Если же выражение exp не ссылается на корректный объект, вызывается исключительная ситуация __non_rtti_object.
В приведенном ниже примере программы иллюстрируется полиморфизм на этапе выполнения программы, обеспечиваемый виртуальными функциями. В нем также демонстрируется и работа невиртуальных функций в иерархии классов. // dynamic_cast_8.cpp // compile with: /GR /EHsc #include <stdio.h> #include <iostream>
struct A { virtual void test() { printf_s("in A\n"); } };
struct B : A { virtual void test() { printf_s("in B\n"); } void test2() { printf_s("test2 in B\n"); } };
struct C : B { virtual void test() { printf_s("in C\n");} void test2() { printf_s("test2 in C\n"); } };
void Globaltest(A& a) { try { C &c = dynamic_cast<C&>(a); printf_s("in GlobalTest\n"); } catch(std::bad_cast) { printf_s("Can't cast to C\n"); } }
int main() { A *pa = new C; A *pa2 = new B; pa->test(); B * pb = dynamic_cast<B *>(pa); if (pb) pb->test2();
C * pc = dynamic_cast<C *>(pa2); if (pc) pc->test2(); C ConStack; Globaltest(ConStack);
/* следующий код вызовет ошибку, так как объект типа B ничего не знает об объекте типа C */ B BonStack; Globaltest(BonStack); }
Вывод программы: in C test2 in B in GlobalTest Can't cast to C
|
|||
Последнее изменение этой страницы: 2018-04-12; просмотров: 392. stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда... |