Студопедия

КАТЕГОРИИ:

АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Преобразование полиморфных типов 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" потому, что он перемещает указатель вниз по иерархии классов, от родительского класса к производному, т.е. наследуемому.

Замечание. Правила преобразования типов при множественном наследовании см. в MSDN

 

Если в операции

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 не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда...