Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Языки программирования. Практический сравнитель...doc
Скачиваний:
54
Добавлен:
09.09.2019
Размер:
2.68 Mб
Скачать

9.5. Упражнения

1. Какие типы с плавающей точкой существуют на вашем компьютере? Пе­речислите диапазон и точность представления для каждого типа. Ис­пользуется ли смещение в представлении экспоненты? Выполняется ли нормализация? Есть ли скрытый старший бит? Существует ли представ­ление бесконечности или других необычных значений?

2. Напишите программу, которая берет число с плавающей точкой и печа­тает знак, мантиссу и экспоненту (после удаления всех смещений).

3. Напишите программу для целочисленного сложения и умножения с не­ограниченной точностью.

4. Напишите программу для печати двоичного представления десятичной дроби.

5. Напишите программу для BCD-арифметики.

6. Напишите программу для эмуляции сложения и умножения с плаваю­щей точкой.

7. Объявите различные типы с фиксированной точкой в Ada и проверьте, как представляются значения. Как представляется тип Duration?

8. В Ada существуют ограничения на арифметику с фиксированной точкой. Перечислите и обоснуйте каждое ограничение.

Глава 10

Полиморфизм

Полиморфизм означает «многоформенность». Здесь мы этим термином обозначаем возможность для программиста использовать переменную, значе­ние или подпрограмму двумя или несколькими различными способами. По­лиморфизм почти по определению является источником ошибок; достаточно трудно понять программу даже тогда, когда каждое имя имеет одно значение, и намного труднее, если имя может иметь множество значений! Однако во многих случаях полиморфизм необходим и достаточно надежен при аккурат­ном применении.

Полиморфизм может быть статическим или динамическим. В статическом полиморфизме множественные формы разрешаются (конкретизируются) на этапе компиляции, и генерируется соответствующий машинный код. Напри­мер:

• преобразование типов: значение преобразуется из одного типа в другой;

• перегрузка (overloading): одно и то же имя используется для двух или не­скольких разных объектов или подпрограмм (включая операции);

• родовой (настраиваемый) сегмент: параметризованный шаблон под­программы используется для создания различных конкретных экземпля­ров подпрограммы.

В динамическом полиморфизме структурная неопределенность остается до этапа выполнения:

• вариантные и неограниченные записи: одна переменная может иметь значения разных типов;

• диспетчеризация во время выполнения: выбор подпрограммы, которую нужно вызвать, делается при выполнении.

10.1. Преобразование типов

Преобразование типов — это операция преобразования значения одного типа к значению другого типа. Существуют два варианта преобразования типов: 1) пе­ревод значения одного типа к допустимому значению другого типа, и 2) пере­сылка значения как неинтерпретируемой строки битов.

Преобразование числовых значений, скажем, значений с плавающей точ­кой, к целочисленным включает выполнение команд преобразования битов значения с плавающей точкой так, чтобы они представили соответствующее целое число. Фактически, преобразование типов делается функцией, получа­ющей параметр одного типа и возвращающей результат другого типа. Синтак­сис языка Ada для преобразования типов такой же, как у функции:

Ada

I: Integer := 5; F:

Float := Float(l);

в то время как синтаксис языка С может показаться странным, особенно в сложном выражении:

C


int i = 5;

float f = (float) i;

В C++ для совместимости сохранен синтаксис С, но для улучшения читаемо- сти программы также введен и функциональный синтаксис, как в Ada. Кроме того, и С, и C++ включают неявные преобразования между типами, прежде всего числовыми:

C

int i; float f = i;

Явные преобразования типов безопасны, потому что они являются всего

лишь функциями: если не существует встроенное преобразование типа, вы

всегда можете написать свое собственное. Неявные преобразования типов более проблематичны, потому что читатель программы никогда не знает, было

преобразование преднамеренным или это просто оплошность. Использование целочисленных значений в сложном выражении с плавающей точкой не должно вызывать никаких проблем, но другие преобразования следует указывать явно.

Вторая форма преобразования типов просто разрешает программе исполь-зовать одну и ту же строку битов двумя разными способами. К сожалению, в языке С используется один и тот же синтаксис для обеих форм преобразова-ния: если преобразование типов имеет смысл, например между числовыми типами или указательными типами, то оно выполняется; иначе строка битов передается, как есть.

В языке Ada можно между любыми двумя типами осуществить не контролируемое преобразование (unchecked conversion), при котором значение трактуется как неинтерпретируемая строка битов. Поскольку это небезопасно по самой сути и разрушает все с таким трудом добытые преимущества контроля типов, неконтролируемые преобразования не поощряются, и син­таксис языка спроектирован так, чтобы такие преобразования бросались в глаза. При просмотре программы вы не пропустите места таких преобразова­ний и должны будете «оправдаться» хотя бы перед собой.

Хотя для совместимости в C++ сохранено такое же преобразование типов, как в С, в нем определен новый набор операций преобразования типов:

• dynamic_cast. См. раздел 15.3.

• static_cast. Выражение типа Т1 может статически приводиться к типу Т2, если Т1 может быть неявно преобразовано к Т2 или обратно; static_cast следует использовать для безопасных преобразований типов, как, напри­мер, float к int или обратно.

• reinterpret_cast. Небезопасные преобразования типов.

• const_cast. Используется, чтобы разрешить делать присваивания кон­стантным объектам.