Р.У. Себеста - Основные копцепции языков программирования (2001) (1160794), страница 76
Текст из файла (страница 76)
часто возникающие вследствие перегрузки оператора "минус". Проблема со. лько в том, что компилятор не может указать, интерпретируется ли оператор как - -ып нли как унарный. Поэтому повторимся: если вы забыли включить первый опе. лразумевая использование оператора как бинарного, то компилятор не опредеьзк ошибку. Впрочем, в этом случае значения унарной и бинарной операции хотя .. - э связаны, так что читабельность в этом случае не страдает. ...ествование отдельных операторных символов для указания операций не только лвает читабельность, их использование иногда бывает удобным в общих операми'"лмсром может служить оператор деления.
Рассмотрим проблему поиска среднего : "етнческого для набора целых чисел, причем среднее требуется найти в виде числа ..-зющей точкой. Обычно сумма целых чисел вычисляется как целое число. Предпо'.. что это было выполнено, и значение суммы всех чисел мы присвоили перемен: .—. а количество этих чисел — переменной соипг. Если теперь нам требуется вы.
- -ь среднее в виде числа с плавающей точкой и присвоить его переменной ач9. то в °: ~ — это может быть выполнено следующим образолк — вцгя / соцпс; :-'.. в большинстве случаев такое присваивание приведет к неверному результату. ..:.; ьку оба операнда оператора деления принадлежат к целому типу, то выполняется :гзция целочисленного деления, результат которой усекается до целого числа. Поэто-есмотря на принадлежность целевой переменной (ачба) к типу чисел с плавающей и. ее значение не будет содержать дробной части. Целочисленный результат деле= зреобразовывается в тип чисел с плавающей точкой после отбрасывания дробной происходящего в процессе целочисленного деления. 'лт/ация упрощается при наличии операторного символа для деления чисел с пла-.глей точкой. В языке Разсай например, символ / обозначает леление чисел с плаей точкой, поэтому можно использовать следующее присваивание вшп / се нас г .:ь переменная ач9 принадлежит к типу с плавающей точкой, а переменные вим и .:.: — к целому.
Оба операнда операции деления неявно преобразуются в тип чисел с :воющей точкой, после чего будет выполнено деление чисел с плавающей точкой. К ..и) типу неявного преобразования мы еше вернемся в следующем разделе, а сейчас -метим, что целочисленное деление в языке Разса! задается оператором глхч, принизюшим целые операнды и выдающим целочисленный результат.
Если же в языке нет -.ельного оператора, выполняющего деление чисел с плавающей точкой, то должно ; пользоваться явное преобразование типов, рассматриваемое в разлеле 6.4.2. Некоторые языки, поддерживающие абстрактные типы данных (см. главу! О), наприер языки Аоа, С++ и ГОКТКАМ 90, разрешают программисту дальнейшую перегрузку :ераторных символов. Предположим, что пользователь желает определить оператор * ежду целым скаляром и целочисленным массивом для умножения каждою элемента засова на скаляр. Это можно сделать, написав функцию-подпрограмму с именем +, вы- б.3. Перегруженные операторы полняюшую эту новую операцию. При употреблении этого оператора компилятор, как и при встроенных перегрузках операторов, выберет нужное его значение, основываясь на значениях типов операндов.
Если, например, новое определение оператора * давалось в программе на языке Аба, то компилятор будет использовать это новое значение везде. где оператор появится с целым числом в качестве левого операнда и с целочисленным массивом в качестве правого. При разумном использовании определяемые пользователем перегрузки операторов могут облегчить читабельность программ. Если, например, операторы ь и * были перегружены для выполнения действий с абстрактными матричными типами, а переменные А.
В, С и Э принадлежат к этому типу, то вместо выражения МасгзхАбб)МакгдхМц1с(А, В), Масг1хМц1с(С, 0) ) может использоваться выражение А*В+С*() С другой стороны, определяемая пользователем перегрузка может навредить надежности. Например, ничто не мешает пользователю определить оператор ь для обозначения операции умножения. Более того, обнаружив в программе оператор *, читатель, чтобы определить сго значение, должен найти и тнп операндов, и определение оператора, причем любое или даже все эти определения могут нахолиться в других файлах.
Язык С++ содержит несколько операторов, перегрузить которые невозможно. Среди них: оператор принадлежности к классу или структуре (. ) и оператор разрешения области видимости (::). Интересно отметить, что перегрузка операторов является одним из свойств языка С++, не включенных в язык Зача. 6.4. Преобразования типов Преобразования типов бывают сужаюшими и расширяющими. Сужаюшее преобразование (папоцбпй сопкепйоп) трансформирует величину в тип, который не может содержать даже приближений всех значениЯ исходного типа. Пример; преобразование типа боцЬ1е в тип х1оас языка С (диапазон значений типа с(оцЬ1е значительно больше, чем у типа к1оак). Расширяющее преобразование (вббеп)пя соптегз|оп), наоборот, трансформирует величину в тип, который может содержать, как минимум, приближения всех значений исходного типа.
В качестве примера можно привести преобразование типа дик в тип к1оак языка С. Расширяющее преобразование безопасно практически всегда, тогда как сужаюшее — нет. В качестве примера потенциальной проблемы, связанной с расширяющим преобразованием. можно назвать следующую. Несмотря на то что преобразование целых чисел в числа с плавающей точкой относится к расширяющим, во многих реализациях языков точность представления может теряться.
В некоторых реализациях, например. целые числа имеют размер 32 бит памяти, что позволяет хранить не менее девяти значащих десятичных цифр. Значения с плавающей точкой во многих случаях также имеют размер 32 бнт, допускающий точность только в семь десятичных цифр. Таким образом, расширяющее преобразование целой величины в величину с плавающей точкой может привести к потере точности в размере двух цифр.
Преобразования типов могут быть явными и неявными. В следующих двух разделах рассматриваются оба. 2ВВ Глава б. Вырожвиня и опвраторы присваивания Ь.4.1. Приведение типов в выражениях Одно из конструкторских решений относительно арифметических выражений связано ; нашчием у оператора операндов различных типов. Поскольку компьютер обычно не .сдержит бинарных операций, принимающих операнды различных типов, то в языках, ;. -)скаюших существование подобных выражений. называемых смешаннымн выра,кениями (щ(хек-щоде ехргеззюпз), должны определяться соглашения для неявного прн-...:. иця типов операндов. Напомним, что в главе 4 мы определили инициируемое ком-; -.ятором преобразование типов как неявное. Для преобразования типов, явно залавае" го программистом, мы будем использовать термин "явное преобразование типов".
а не сривеэение типов". Хотя некоторые операторные символы мокнут перегружаться,мы будем предполагать, либо на аппаратном, либо на программном уровне компьютера существуют опреде:е-ные в языке операции для каждого типа оператора и операнда. Для перегруженных "ераторов языка, использующего статическое связывание типов, компилятор выбирает - жный тип операции на основе типов операндов. Если в оператор входят два оператора.
--.цналлежаших к разным типам, и такая операция в языке допустима, то компилятор =.л.кен выбрать один из операндов и применить код, реализующий соответствующее -гивезенне типов. Ниже рассматривается несколько проектных решений, относящихся к заработке приведения типов в некоторых языках. Разработчики языка не пришли к единому мнению относительно вопроса о приведе-сл типов арифметических выражений. Противники его широкого использования утвер-.зют. что приведения типов аннулируют выгоды от проверки типов, а следовательно, з-.лают на надежность. Сторонники же включения в язык всех возможных приведениИ - .1ов подходят к этому вопросу с точки зрения гибкости, к потере которой приводит от.
зз от использования приведений типов. Предмет спора заключается в том, должна ли .-ветственность за обнаружение соответствующей категории ошибок возлагаться на -гэграммистов, или же эти ошибки должен обнаруживать компилятор. В качестве простой иллюстрации возникающей проблемы рассмотрим следующую ;.-слезную программу на языке С: чодс( п~азп () ( 1пб а, Ь, с; х1оац с(Г а=Ь*В; Предположим, что в качестве второго операнда оператора умножения планировалось ,.спользовать переменную с, но из-за ошибки при наборе была введена буква б. По;кольку в языке С допустимы смешанные выражения, то компилятор не воспримет это кзк ошибку — он просто вставит команды, приволяшие тип переменной Ь к типу х1оаа.