Основные конструкторы типов.
Как мы уже видели, хотя в языках программирования немало сугубо машинных деталей, в основе системы типов лежит математическая традиция.
Типы строятся, исходя из конечного набора базисных типов (называемых также простыми, примитивными, элементарными), с помощью операций - конструкторов типов.
Большинство конструкторов типов имеют прямые аналоги в математике. Итак, базисные типы - это множества целых чисел, конечных приближений вещественных чисел, литерных значений и, возможно, булевских величин.
Одним из самых простых и понятных конструкторов можно назвать объявление перечисляемого типа. Этот скалярный тип описывается простым перечислением его компонент. Хотя с теоретической точки зрения скалярные типы данных могут полностью удовлетворить потребности программиста, все же желательно иметь практическую возможность определять свои неструктурные типы, и их помощью можно более четко описать предполагаемую потенциальную область значений переменной и обеспечить возможность эффективного представления переменной. Объявление переменной перечисляемого типа определяет список именованных констант, называемый списком перечисления. Каждому элементу списка перечисления ставится в соответствие целое число. Поэтому переменной перечисляемого типа выделяется столько же памяти, сколько и для переменной типа int. Над объектами перечисляемого типа определены те же операции, что и над объектами целого типа.
enum {компонента1,...,компонентаn};
enum TColor {WHITE, YELLOW, RED, GREEN, BLUE, BLACK};
:
Tcolor color1 = WHITE, color2;
color2 = color1;
Теперь поговорим немного о другом классе типов. Это так называемые структурные типы данных. Структурные типы предоставляют возможность давать коллективное имя некоторому множеству элементов. Существует несколько способов структурирования, каждый из которых отличается способом доступа к индивидуальным компонентам. Для определения типа структурной переменной необходимо задать:
1. способ структурирования,
2. типы компонент.
Важнейшие конструкторы таких типов - это массивы и записи (структуры).
Массив позволяет хранить как единое целое последовательность переменных одного типа. Переменная, имеющая структуру массива, является совокупностью компонент-переменных одного и того же типа. У массива, однако, есть характерные особенности:
1. Каждая отдельная компонента массива может быть явно обозначена и к ней имеется прямой доступ.
2. Число компонент массива определяется при его описании и в дальнейшем не меняется.
Для обозначения компонент используется имя переменной-массива и индекс, который однозначно указывает на желаемый элемент. Тот факт, что индекс может быть вычисляемым объектом, выделяет массив среди других структур данных.
Элементы массива могут быть не только скалярами, но также и структурными компонентами. Если они сами являются массивами, то первоначальный массив называется многомерным.
С абстрактной точки зрения массив можно определить как отображение области одного типа (множество индексов) на множество значений некоторого другого типа (тип элементов). Отображение по-другому называется "функцией". Так что, массивы - это функции с конечной областью определения, то есть функции, определяемые конечной таблицей значений.
Типовой конструктор массивов в языке Си обозначается как [ ].
Тип идентификатор [размер];
В отличие от массива структура позволяет объединить в одном программном объекте совокупность значений, которые могут иметь различные типы. Список объявлений элементов представляет собой последовательность из одного и более переменных. Каждая переменная, объявленная в этом списке, называется элементом структуры. Элементы структуры могут иметь базовый тип, либо быть указателем, структурой. Элемент структуры не может быть того же типа, в которой он содержится, однако им может указатель на тип структуры, в которую он входит.
Типовое выражение, соответствующее конструктору записи
struct
{
тип1 идентификатор1;
:
типn идентификаторn;
};
Структура как конструкция аналогична декартову произведению множеств. Простым примером такого произведения является дата. Для спецификации даты достаточно трех значений: год, месяц, число месяца. Так что вполне логично для описания переменной типа TDate использовать следующую конструкцию:
enum TMonth {Jan, Feb, Mar, ..., Dec};
struct Tdate
{
int Year;
TMonth Month;
int Day;
};
:
TDate BirthDay[10];
BirthDay[3].Year = 1256;
BirthDay[3].Month = Jan;
BirthDay[3].Day = 22;
Пришедшее в язык Си из Алгола 68 понятие объединения union представляет собой размеченное объединение, где элемент множества слагаемого входит во множество с пометкой, указывающей это слагаемое. Объединение позволяет в различные моменты времени хранить в одном объекте значения различного типа. В процессе объявления объединения с ним ассоциируется набор типов значений, которые могут храниться в данном объединении. В каждый момент времени объединение может хранить значение только одного типа из набора.
Память, которая выделяется переменной типа объединение, определяется размером наиболее длинного из элементов объединения. Все элементы размещаются в одной и той же области памяти и с одного и того же адреса. Значение текущего элемента теряется, когда другому элементу объединения присваивается значение. Синтаксически объединение union записывается аналогично struct.
union
{
тип1 идентификатор1;
:
типn идентификаторn;
};
В некоторых языках имеются такие конструкторы типов, как отрезок, множество set (Паскаль), граф.
Особый интерес представляет такой конструктор типов, как указатель pointer. Указатели являются средством построения и обработки структур данных, являющихся, по существу, ориентированными графами с узлами, которые сами могут иметь сложную структуру. Указатель - это переменная, предназначенная для хранения адреса некоторого объекта. Объявление указателя специфицирует имя переменной и тип объекта, на который может указывать эта переменная. Указатель может указывать на значение базового, перечисляемого типа, структуры, объединения, массивы, функции и указатели. В языке Си указатель состоит из адреса, указывающего на объект определенного типа, то есть это типизированный указатель. Приведение указателей к определенному типу позволяет ввести аксиоматику арифметики указателей. Однако, кроме типизированных указателей, существует указатель на пустой тип (void). Указатель на void может указывать на значение любого типа. Однако для выполнения операций над указуемым объектом, необходимо привести тип указателя к типу этого объекта.
Несколько особняком стоят функции. В математике функциям уделяется большое внимание, они являются базовыми объектами. Как мы только что отметили, табличные функции виде массивов входят в систему типов. А как обстоит дело с другими функциями, теми, что представляются в виде подпрограмм (процедур), возвращающих значения?
Тут надо задать вопрос - А что такое данные? Согласно распространенной точке зрения, высказанной Никлаусом Виртом в книге "Алгоритмы + структуры данных = программа", данные - это пассивная, обрабатываемая часть программы. Но функции относятся к активной части программы, и значит, это не данные.
С другой стороны, все, что может быть аргументом ("фактическим параметром") функции, следует считать данными. Но функция, возвращающая значение, может быть использована в качестве аргумента. Какой-то порочный круг.
Выход здесь такой: функции - это данные, но данные особого рода в виду их двойной роли (активной и пассивной) в вычислениях. В языке Си, как и в Алголе 68 функции включаются в систему типов, и тип функции определяется типом возвращаемого значения.
В заключение я хочу привести Вам цитату из книги Хоара [1] по поводу структурной организации типов.
Обсуждая то или иное понятие, человек стремится различить в нем три стороны: идею, формулировку и мотивировку. Идея - это содержательная, интуитивная сторона, суть дела. Формулировка - это математически точное, однозначное выражение идеи. Мотивировка - это подоплека понятия: что за ним стоит, какова его цель, в каком контексте и на каком "фоне" оно возникает.
Рассматривая с этих точек зрения определение Хоара, можно отметить, что идеи, в основном, понятны; формулировки требуют уточнения; желательна более полная мотивировка.
Пытаясь понять, что стоит за идеями и решениями, мы можем увидеть направления дальнейшего движения и факторы, которые оказывают на него влияние.
[назад] | [оглавление] | [вперед] |