И.Г. Головин, И.А. Волкова - Языки и методы программирования, страница 11
Описание файла
PDF-файл из архива "И.Г. Головин, И.А. Волкова - Языки и методы программирования", который расположен в категории "". Всё это находится в предмете "языки программирования" из 7 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Просмотр PDF-файла онлайн
Текст 11 страницы из PDF
Кроме типа c h a r в языке C++ появилсятип wchar t специально для представления символов из UNICODE.Этот тип является целым беззнаковым двухбайтовым типом.Логические типы данныхЛогический тип данных, обозначаемый в языках C++ и C# Javaключевым словом b o o l (b o o le a n в Java), состоит их двух значений:t r u e (истина) и f a l s e (ложь).Набор операций состоит из логического И — «&&», логическогоИли — « | | » и отрицания Не — «!» с обычным математическимсмыслом.Интересной особенностью вычисления логических операций &&и | | является их «ленивость». Ленивость исполнения логическихопераций состоит в том, что они вычисляются слева направо, и еслизначение левого операнда определяет значение всего выражения (дляоперации && это f a l s e , а для операции | | это tr u e ) , то правыеоперанды вычисляться не должны.В языках C# и Java логический тип не может приводиться к целым(да и другим) типам данных (ни явно, ни тем более неявно).49В языке C++ ситуация более сложная.
Дело в том, что логическийтип был включен в язык не сразу, а сначала C++ унаследовал правилаязыка С. В этом языке логические операции были (перечисленныеранее), а отдельного логического типа не было. Логические операциивозвращали целое значение 1 в качестве «истины» и 0 — в качестве«лжи». Если в каком-то месте от выражения произвольного типа требовалось логическое значение, то это выражение (при необходимости) приводилось к целому типу и вычислялось. При этом ненулевоезначение соответствовало «истине», а нулевое — «лжи».
Поэтому наязыке С (и C++) вполне можно записать следующие фрагменты:w h ile (n-m){i f (n > m)n -= m;e lsem -= n;}В языках C# и Java в этом месте компилятор выдаст ошибку,а правильный фрагмент программы имеет видw h ile (n-m != 0) ...То же, конечно, можно записать и на языке C/C++.Таким образом, тип b o o l в языке C++ неявно приводится к целому типу (tr u e — в 1, f a l s e — в 0), и наоборот, что, конечно, снижаетего ценность (по сравнению с логическим типом в C# и Java).Порядковые типы данныхПорядковые типы данных подразделяются на перечислимые типыи типы диапазона.Перечислимый тип задается прямым перечислением константзначений.
Каждое значение задается своим именем.Впервые перечислимые типы появились в языке Паскаль и сразустали популярными как среди разработчиков языков программирования, так и среди программистов. Дело в том, что использование перечислимых типов делает программу более понятной, поскольку всезначения имеют имена, которые характеризуют смысл значения.С точки зрения реализации каждое значение перечислимого типаотображается в целое число, соответствующее его порядковому номеру в определении типа. Этот номер называется ординалом значения.По умолчанию нумерация ординалов начинается с нуля, однако некоторые языки позволяют придать свои значения ординалам.Перечислимые типы реализованы в языках C++, C# и Java (начиная с 2005 г.). Однако в реализации этих типов есть различия.50Начнем с языка C++.
Представим себе задачу моделирования светофора. В н ей ,важную роль имеет цвет светофора, который удобнопредставить перечислимым типом:enum TrafficColors {RED, YELLOW, GREEN};Пусть у нас есть класс TrafficLights, представляющий собойсветофор, и переменная light 1 этого класса. Тогда следующий вызов не нуждается в дополнительных комментариях:lightl.SetSignal(RED);Очевидно, что это переключение светофора в красный цвет.Цвета нумеруются у нас от 0 до 2 (RED=0, YELL0W=1, GREEN=2).Иногда конкретный номер цвета не важен, но мы можем расширитьзадачу, потребовав, чтобы числовые значения констант перечислимого типа соответствовали значениям цветов в цветовой системеRGB-24 (в этой системе каждому цвету соответствует целое значение, составленное из трех байтов — значение каждого байта естьинтенсивность красного, зеленого и синего цветов в диапазоне отОдо 255).Тогда объявление нашего типа изменится (используется шестнадцатеричная форма целых констант — каждая пара цифр соответствуетбайту со значением 255 или 0):enum TrafficColors {RED = OxFFOOOO,YELLOW = OxFFFFOO,GREEN = OxOOFFOO};Теперь значения цветов можно использовать в функциях рисования, требующих указания значения цвета, например:brush.SetBrushColor(YELLOW);Здесь мы предполагаем, что функция SetBrushColor имеет одинпараметр целого типа, означающий цвет в системе RGB-24.Таким образом, значения перечислимого типа неявно преобразуются в значения типа int.
Обратное, однако, неверно. Попытка присвоить переменной перечислимого типа какое-либо целое значениерассматривается компилятором как ошибка:TrafficColors cl = 127; // ошибка! ! !Если мы хотим придать переменной новое числовое значение, тодолжны записать явное преобразование:TrafficColors cl = (TrafficColors)-1;// теперь формально правильно51Однако ясно, что такое преобразование не всегда приводит к ожидаемым результатам (какой реальный цвет будет у переменной c l? ),поэтому и требуется выписывать явное преобразование.Однако у реализации перечислимых типов в языке C++ есть ряднедостатков.
Первый недостаток состоит в том, что константы перечислимого типа имеют ту же область действия, что и имя перечислимого типа (так называемый неявный импорт имен). Это можетприводить к конфликту имен. Например, если мы одновременнопытаемся моделировать семафор, то появляется еще одно перечисление:enum SemaColors {RED, GREEN};Это приводит к конфликту. Для учебных программ это не страшно (имена в своих программах поменять легко).
Однако в условияхиндустриального программирования, когда широко используютсябиблиотеки сторонних производителей (например, одна библиотекамоделирует светофор, другая — семафор), такие конфликты доставляют немало хлопот программистам.Вторым недостатком является фиксированное представлениеперечислимых типов в языке C++, поскольку они всегда реализуютсякак целые (на базе основного целого типа in t ) .
Иногда это неудобно и приводит к напрасной трате памяти (ведь хватило бы и болеекороткого типа).В языке C# эти недостатки преодолены. Заметим, что приведенные ранее объявления типов TrafficColors и SemaColors являются вполне корректными в языке C# (надо только убрать концевыеточки с запятой). Однако имена перечислимых констант локализованы в типе и могут использоваться за пределами объявления типатолько в видеимя типа.имя_константыНапример:lightl.SetSignal (TrafficColors .RED) ;Кроме того, значения перечислимого типа могут храниться какзначения любого целочисленного типа (такой тип называется базовым для перечисления).
По умолчанию базовым является основнойцелый тип i n t , но базовый тип легко поменять:enum SemaColors : byte{Red, Green}В отличие от языка C++ значения перечислимых типов в C# должны преобразовываться в базовый тип только явно:52brush .SetBrushColor (TrafficColors .YELLOW) ;// в C# - ошибка — SetBrushColor требует целый типbrush .SetBrushColor ( (int) TrafficColors .YELLOW) ;// теперь правильно!В языке Java перечислимые типы появились относительно недавно(с 2005 г.) и реализованы они наиболее «экзотично»: на самом делеперечислимые типы в Java — это классы. Не вдаваясь в тонкости(о них можно прочитать, например, в [35]), заметим, что объявлениеи использование перечислений здесь внешне похожи на С#:enum TrafficColors{Red, Yellow, Blue}TrafficColors cl = TrafficColors .Yellow;Неявные преобразования в целый тип и обратно также запрещены,но можно использовать методы перечислимого класса ordinal (),возвращающий порядковый номер константы, и values () , возвращающий массив констант значений перечислимого типа (индексв массиве — это номер константы в типе):int colorNumber = TrafficColors Red.ordinal () ;// colorNumber получает значение 0TrafficColors с =TrafficColors .values [colorNumber+1 ] ;// с получает значение TrafficColors.
YellowНапоследок заметим, что во всех рассмотренных языках к перечислимым типам применимы операции сравнения (сравниваютсяординалы значений).Скажем несколько слов о диапазонных типах. Они появилисьв языке Паскаль и позволяли ограничить значения какого-либо целого или перечислимого типа.Например:type Index = 0..N; // диапазон целого типаtype DaysOfWeek = (Mon, Tue, Wed, Thu, Fri, Sat,Sun) ;// перечислимый тип — дни неделиtype WorkDays = Mon..Fri;// диапазон типа DaysOfWeekWeekendDays = Sat..Sun;// другой диапазон DaysOfWeekЧаще всего диапазонные типы используются в качестве типа индекса в массивах.