Г. Шилтд - Самоучитель C++ (DJVU) (1114955), страница 54
Текст из файла (страница 54)
Хотя получение имени типа объекта в некоторых ситуациях оказывается весьма полезным, часто бывает необходимо узнать, соответствуют ли друг другу типы нескольких объектов. Это легко сделать, зная что объект типа 1уре шло, возвращаемый оператором 1уреЫ, перегружает операторы == и!=, В представленной ниже программе показано использование этих операторов. и )= с оператором гуреЫ // Использование операторов == ()1пс1вбе <1ояетваво ()1пс1пбе <суреьпйо> пя(пц пагпеярасе яМ; с)аяв Х ( т1гсаа1 чоЫ Й() () ) ." с1аяя у ч1гсиа1 мог 1 1 () 1пс ваап() ( Х х1, х2; у у),; 1Г (СуреЫ(х1) = — — (Суре1с((х2) ) соус « "тип объектов х1 и х2 одинаков1п"! а1яа соас « "ттк~ объектов х1 и х2 не одинаков 1п"г 1В (Турагс) (х1) )= ( Суре1с((у1) ) соас « "тип объектов х1 и у1 не одинаков хп"; е1яе соус « "тип объектов х1 и у1 одинаковхп"г гегпгп О; Программа выводит на экран следующую информацию: Тип объектов х! и х2 одинаков Тип объектов х! и у! не одинаков 4.
Хотя в предыдущих примерах и были показаны некоторые приемы работы с оператором туре Ыо, главных его достоинств мы не увидели, поскольку типы объектов были известны уже на этапе компиляции программы. В сле- 3б4 Самоучитель чоЫ ехатр1е () ( Фабрика производнык от класса Я)1аре объектов Кларе *депегалол() 11пе," тебпгп Ы()ЬЬ; 1псжа1п ( ) ( 1 п~- Яйаре *р! аког(1=-0; 1<10; 1+.~) р = депегаког (); !1 создание следующего объекта сои « суреЫ(+р) .паве() «епс(1р рисует объект, если он не типа Мп11впаре Фй (буреЫ(*р) ! =- ~уре1б (Ип11Жаре) ) р->ехатр1е ( ); геспгп 0; Программа выводит на экран следующее: с1аяя Кессапц1е Ф~**+ * ~ Ф с1аяя Ип11Я)заре с1аяя Тг1апд1е аиИсЬ(гапс(() о, 4) саяе 0: гевпгп пеи саяе 1: гелпгп пеи саяе 2; гелпгп пеи саяе 3: геспгп пеи Кесвапд1е; Тггапд1ер Ип11Япаре; 265 Глава 12. динамическая идентификация и приведение типов с1аяв залпе с~ аяя КесСапсх1 е *»*»» Ф * Ыпе с1аяя с1аяя тт1апд1е *»»*» с1аяя тттапд1е * » * **** с1аяя Тт1апд1е » »*Ф *» с1аяя Ьтпе »**»Ф 5.
Оператор $уреЫ может работать с классами-шаблонами. Например, рассмотрим следующую программу. В ней для хранения некоторых значений создается иерархия классов-шаблонов. Виртуальная функция цеФ та19 возвращает определенное в каждом классе значение. Для класса Хпгп это значение соответствует самому числу. Для класса Яйааге — это квадрат числа. Для класса Яйг гоо1 — это квадратный корень числа. Объекты, производные от класса Хшп, генерирует функция репеяа1ог(). С помощью оператора 1уреЫ определяется тип генерируемых объектов. // Использование оператора 1уреЫ с шаблонами Фъпс1сйе <Ыв скеахп> Ипс1ис1е <свМИЬ> 1йпс!оде <схватп Мпс1сое <Суре1пйо> цяп~ пагпеврасе вестах сехвр1асе <с1авв Т> с1авв Хптп 1 риЬИс: Т х; Моха(Т й ( х = з.; 387 Глава 12. Динамическая идентификация и приведение типов 1Г (Гуреьс((*р1) == Гурегс((Яс)вагу<с)оиЫе>) ) сопс « "Квадрат объекта: 16 (Гуреус((*р1) == Гуре1с((вс(г гооГ<с(оиЫе>) ) сопб « "Квадратный корень объекта: сопс « "Значение равно: " « р1->дег ча1() сопс « епб1; гесигп О) Программа выводит на экран следующее: с1авв Зита<с(оиЫе> с1авв 8с)вагу<с(оиЫе> с1авв Зс(г гоо(<с)оиЫе> )е Яс)нату<с)онЫе> Значение равно: 10000 Теперь генерируем объекты Квадратный корень объекта..
Значение равно: Квадрат объекта: Значение равно: 0 Квадратный корень объекта: Значение равно: Квадрат объекта: Значение равно: 3364 Квадрат обьекта: Значение равно: 4096 Квадратный корень объекта: Значение равно: Квадраты ый корень объекта: Значение равно: Квадратньгг корень объекта: Значение равно: Квадратный корень объекта: Значение равно: Квадратный корень объекта: Значение равно: 8.18535 4,89898 б. 7082 5. 19616 9. 53939 б.
48074 б 1. Зачем нужна динамическая идентификация типа? 2. Проведите эксперимент, о котором говорилось в примере 1. Что вы увидите на экране? 3. Правилен ли следующий фрагмент программы? соцс « Гуре1с((Е1оаГ) .пате() с)аев В ( ч1гбпа1 чо16( г() () 4. Дан фрагмент программы. Как определить, является ли р указателем на объект типа Р2? 368 Самоучитель С++ с1аьв ()1: риЬ1(с В Г ~с1<( гО () с1аае ТЭ2 РиЫ1с В ( чо!Й ~() () )> 1п( п~а~п () В *Р1 5. По отношению к классу Ииш из примера 5 следующее выражение является истинным или ложным ) еуреЫ (Ныт<вп~>) == ~уретс((нап<с(сиЬ1е>) б.
Поэкспериментируйте с КТТ1. Хотя польза от динамической идентификации типа в контексте приведенных здесь простых примеров может показаться не слишком очевидной, тем не менее это мощный инструмент управления объектами во время работы программы. 12.2. Оператор бупаипс сазФ Хотя в С++ продолжают поддерживаться характерные для языка С операторы приведения типов, имеется и несколько новых. Это операторы ((удаш1с сав1, сопаФ саяФ, гешгегргеГ сааФ и вгЫ(с савФ. Поскольку оператор йуиашс см$ имеет непосредственное отношение к динамической идентификации типа, мы рассмотрим его первым. Остальные операторы приведения типов рассматриваются в следующем разделе. Оператор 4упаш1с сав$ реализует приведение типов в динамическом режиме, что позволяет контролировать правильность этой операции во время работы программы.
Если при выполнении оператора аупаш1с сав1 приведения типов не произошло, будет выдана ошибка приведения типов. Ниже представлена основная форма оператора дупаппс сав1: йупапйс савЕ<целваой тип> (вирахекна) Здесь целевой тип — это тип, которым должен стать тип параметра вьдажвиив после выполнения операции приведения типов. Целевой тип должен быть типом указателя или ссылки и результат выполнения параметра выражение тоже должен стать указателем или ссылкой. Таким образом, оператор йуаапйс сав$ используется для приведения типа одного указателя к типу другого или типа одной ссылки к типу другой.
Основное назначение оператора дупаш1с сав$ заключается в реализации операции приведения полиморфных типов. Например, пусть дано два поли- Глава Ю, Динамическая идентификация и приведение типов морфных класса В и Р, причем класс Р является производным от класса В, тогда оператор аупаппс саМ всегда может привести тип указателя Р* к типу указателя В*. Это возможно потому, что указатель базового класса всегда может указывать на объект производного класса. Оператор Йуваш1е еаЫ может также привести тип указателя В* к типу указателя Э*, но только в том случае, если объект, на который указывает указатель, действительно является объектом типа Р.
Как правило, оператор дупяиис саят выполняется успешно, когда указатель (или ссылка) после приведения типов становится указателем (или ссылкой) либо на объект целевого типа, либо на объект производного от целевого типа. В противном случае приведения типов не происходит. При неудачной попытке приведения типов результатом выполнения оператора «упадке ая$1 является нуль, если в операции использовались указатели.
Если же в операции использовались ссылки, возбуждается исключительная ситуация Ьаа саз1. Рассмотрим простой пример. Предположим, что Вазе — это базовый класс, а Репчев — это класс, производный от класса Вазе. Базе *Ьр, Ь оЬ," Рег~лтеб «бр, б оЬ; Ьр = аб оЬ; // указатель базового класса // указывает на обьект производного класса бр = оупаштс сааг<пегтчеб «> (Ьр) 1ЕП с~р) сонь "приведение типов прошло успешно"; Здесь приведение типа указателя Ьр базового класса к типу указателя ар производного класса прошло успешно, поскольку указатель Ьр на самом деле указывает на объект производного класса Репчев. Таким образом, после выполнения этого фрагмента программы на экране появится сообщение Приведение типов прошло успешно.
Однако в следующем фрагменте операция приведения типов заканчивается неудачей, поскольку указатель Ьр указывает на объект базового класса Вазе, а приводить тип объекта базового класса к типу объекта производного класса неправильно. Ьр = «Ь оЬ; // указатель базового класса // указывает на объект базового класса бр = цуьмпгс сааккцеггчео *> [Ьр~ гЙ Псф) сопл "приведеюгя типов не произошло"; Поскольку попытка приведения типов закончилась неудачей, на экран будет выведено сообщение Приведения типов ие произошло. Оператор фяяййс еяя1 в некоторых случаях можно использовать вместо оператора (уреИ.
Например, опять предположим, что Вазе — это базовый класс, а Репчеа — это класс, производный от класса Вазе. В следующем фрагменте указателю вр присваивается адрес объекта, на который указывает указатель Ьр, но только в том случае, если это действительно объект класса Репчеа. 370 Самоучитель С-н- Ваке Ьр; Рспчес1 с(р; О з.с(сурЕЫ( Ьр) == суреъс((оеегчес(] ) ор = (Репчес) *) Ьр„. В данном примере для фактического выполнения операции приведения типов используется стиль языка С.