Перейти на главную страницу
Не обращая больше внимания на ущербность терминологии, займемся содержанием понятия АТД. Как мы видели, наличие перечисляемых, уточняемых и конструируемых типов данных в сочетании со средствами выделения динамической памяти позволяет конструировать и использовать структуры данных, достаточные для создания произвольно сложных программ. Ограниченность этих средств состоит в том, что при определении типов и создании структур невозможно зафиксировать правила их использования. Например, если определен структурный тип с полями salary, commissions и total в предположении, что для любой переменной этого типа поле total всегда будет содержать общую сумму выплат, то ничто не мешает по ошибке нарушить это условие (с точки зрения компилятора никакой ошибки нет) и получить неверные результаты работы программы.
Основной идеей АТД является то, что при его определении специфицируется не только структура значений типа, но и набор допустимых операций над переменными и значениями этого типа. В наиболее сильном случае доступ к внутренней структуре типа доступен только через его операции. В число операций обязаны входить один или несколько конструкторов значений типа.
Имеется много разновидностей языков с АТД, языковые средства которых весьма различаются. Кроме того, к этому семейству языков примыкают языки объектно-ориентированного программирования. По поводу них одни авторы (к числу которых относится и автор этой книги) полагают, что для них термин "язык объектно-ориентированного программирования" является модной заменой старого термина "язык с АТД". Другие находят между этими языковыми семействами много тонких отличий, часть которых считают серьезными. Мы не будем глубоко анализировать эти дискуссии, а обсудим некоторые базовые концепции, общие для обоих семейств.
Подобная внешняя характеристика АТД называется его представлением или спецификацией. Представление включает имя АТД и набор спецификаций доступных пользователю операций со значениями этого типа. Со своей стороны, спецификация операции состоит из имени и типов параметров (в последнее время такие спецификации принято называть сигнатурами операций). Для однозначного определения компилятором того, какая реально функция или процедура должна быть вызвана при обращении к операции, обычно требуют, чтобы сигнатуры всех операций всех АТД, используемых в программе, были различны (мы еще вернемся к этой теме ниже при обсуждении возможностей полиморфизма).
Переменные, используемые для внутреннего представления значений типа называются переменными состояния, а их совокупность состоянием значений.
Иногда исходя из соображений эффективности допускается прямой доступ к некоторым переменным состояния значений типа (путем использования обычных предопределенных операций чтения и записи). В этом случае переменные состояния, доступные в таком режиме, также специфицируются во внешнем представлении типа.
Иногда для целей реализации типа бывает полезно иметь в составе его операций такие, которые недоступны для внешнего использования и носят служебный характер. Такие функции и/или процедуры специальным образом помечаются в реализации типа (например, как приватные), и их сигнатуры не включаются во внешнюю спецификацию типа. Переменные состояния, которые должны быть прямо доступны для внешнего использования, также помечаются специальным образом.
В строго типизированных языках с абстрактными типами данных спецификация типа скрывает его реализацию. Внешнее представление типа инкапсулирует особенности его структурной и операционной реализации. До сих пор продолжаются споры о том, что является идеальной инкапсуляцией типа. В частности, многие полагают, что разрешение прямого доступа к переменным состояния нарушает принципы инкапсуляции. По всей видимости, это неверно. Если все возможные операции со значениями типа строго специфицированы в его внешнем представлении, то в любом случае могут допускаться различные реализации типа. Но, естественно, чем более высоким уровнем обладает спецификация, тем больше свобода при выборе реализации.
В отличие от этого, при использовании механизма наследования типов требуется, чтобы спецификация нового типа (подтипа) полностью включала спецификацию наследуемого типа (супертипа). Но эта спецификация может быть расширена сигнатурами дополнительных операций, вводимых для подтипа. Соответственно в реализации подтипа должны присутствовать коды функций и/или процедур дополнительных операций, а структуры данных, функции и процедуры супертипа могут быть переопределены.
В разных языках с абстрактными типами данных допускается либо только простое наследование типов (для каждого подтипа существует только один супертип), либо множественное наследование (для подтипа может существовать несколько супертипов). Множественное наследование порождает проблему согласования сигнатур операций супертипов. Общего решения этой проблемы не существует, в каждом из языков с множественным наследованием используются свои приемы. Мы не будем более подробно останавливаться на этих деталях.
Имеются два основных соображения по поводу пользы механизма наследования типов. Во-первых, этот механизм обеспечивает возможность контролируемого и дисциплинированного повторного использования программных кодов. Во-вторых (и может быть, это даже более важно), во многих языках используется так называемая семантика включения: считается, что значение любого подтипа одновременно является значением любого своего супертипа. Семантика включения хорошо соответствует смыслу механизма наследования как средства уточненной классификации объектов предметной области.
Естественно, что в подтипах типа "Человек" появляются дополнительные операции, например, "размер пособия" для безработных и "должностной оклад" для служащих. Можно предположить, что операция "знание языков", вводимая для типа "Служащий", по-разному переопределяется для его подтипов "Программист" и "Преподаватель".
С другой стороны, очевидно, что из соображений здравого смысла и безработные, и служащие обладают общими свойствами, характерными для типа "Человек", а программисты и преподаватели относятся к категории "Служащие". Эти соображения приводят нас к иерархии включения значений этих типов данных. Это означает, что, в частности, должна иметься возможность единообразной работы со значениями типа "Человек" независимо от того, сформировано ли соответствующее значение конструктором этого типа или же конструктором любого из его подтипов. Конечно, при этом можно использовать только те операции, которые специфицированы во внешнем представлении типа "Человек".
Поскольку в подтипе может быть переопределена реализация операций, специфицированных в супертипе, то во время компиляции программы иногда невозможно установить, какую функцию или процедуру требуется вызывать при выполнении операции над значением типа. По этой причине в системах программирования, поддерживающих развитый механизм наследования, для обеспечения корректного вызова функций и/или процедур, которые реализуют операции типа, приходится применять так называемый метод позднего связывания (late binding).
Суть этого метода состоит в том, что во время выполнения программы при каждом значении (или объекте в языках объектно-ориентированного программирования) содержится информация о типе, с помощью конструктора которого было создано это значение. На основе этой информации на стадии выполнения удается обнаружить требуемые реализации операций. Понятно, что применение метода позднего связывания вносит в процесс выполнения программы существенный элемент интерпретации, что приводит к снижению эффективности. Поэтому, по мере возможности, стремятся снизить накладные расходы даже за счет понижения универсальности механизма наследования. Примером может служить аппарат виртуальных функций в языке Си++.
Как кажется, основной причиной появления полиморфизма первого типа является желание использовать для обозначения операций абстрактных типов привычные знаки операций, принятые во встроенных типах данных. Например, если определяется абстрактный тип данных "комплексные числа", то было бы естественно использовать знак "+" для обозначения сложения, "-" - для обозначения вычитания и т.д. Кроме того, для того же типа хотелось бы использовать один и тот же знак "+" для обозначения операций сложения двух комплексных чисел, сложения комплексного числа с вещественным и вещественного с комплексным.
Технику, обеспечивающую возможность ввести новую интерпретацию уже используемых знаков операций и/или имен функций и процедур, принято называть "перегрузкой". Перегрузка существует и в языках, не поддерживающих абстрактные типы данных, в частности, в языке программирования Ада. Но, с нашей точки зрения, особенно существенны возможности перегрузки именно в языках с абстрактными типами данных.
Преимуществом полиморфизма на основе перегрузки является то, что для его поддержки требуется не слишком существенное усложнение компилятора и не возникают дополнительные накладные расходы во время выполнения программы. Обычно реализация основывается на использовании сигнатур функций и процедур. При соблюдении обязательного требования различия сигнатур всех одноименных функций и процедур достаточно просто придумать правила формирования расширенных имен на основе основного имени функции или процедуры и имен типов ее параметров. Если язык достаточно строго типизирован, и сигнатура любой доступной функции или процедуры находится в области видимости компилятора, то по имени и составу фактических параметров вызова можно определить расширенное имя требуемой подпрограммы. (Заметим, что если бы в программах на языке Си использование прототипов функций было бы обязательным, то можно было бы реализовать перегрузку имен функций и соответствующий полиморфизм даже в компиляторах чистого Си).
Второй род полиморфизма операций типов и реализующих их функций и процедур возникает при переопределении в подтипе реализации операций супертипа. Как мы отмечали в предыдущем разделе, в этом случае сигнатуры операций изменяться не должны, и мы получаем разные реализации операции с одной сигнатурой. В этом случае возникающие неоднозначности невозможно разрешить во время компиляции программы, и приходится использовать упоминавшийся в предыдущем разделе метод позднего связывания.
Тем самым, хотя отмеченные виды полиморфизма на первый взгляд кажутся очень близкими, они существенно по-разному реализуются и порождают существенно разные накладные расходы. При всей привлекательности возможности переопределения операций в подтипах ими следует пользоваться осмотрительно.
Практически все современные реляционные СУБД опираются на стандартный язык баз данных SQL и поддерживают встроенные типы данных, специфицированные в этом языке. Если не вдаваться в синтаксические детали, то типы данных в стандарте языка SQL/92 определяются следующим образом:
Тип данных определяется как множество представляющих его значений. Логическим представлением значения является литерал. Физическое представление зависит от реализации.
Значение любого типа является примитивным в том смысле, что в соответствии со стандартом оно не может быть логически разбито на другие значения. Значения могут быть определенными или неопределенными. Неопределенное значение - это зависящее от реализации значение, которое гарантированно отлично от любого определенного значения соответствующего типа. Можно считать, что имеется всего одно неопределенное значение, входящее в любой тип данных языка SQL. Для неопределенного значения отсутствует представляющий его литерал, хотя в некоторых случаях используется ключевое слово NULL для выражения того, что желательно именно неопределенное значение.
SQL/92 определяются типы данных, обозначаемые следующими ключевыми словами: CHARACTER, CHARACTER VARYING, BIT, BIT VARYING, NUMERIC, DECIMAL, INTEGER, SMALLINT, FLOAT, REAL, DOUBLE PRECISION, DATE, TIME, TIMESTAMP и INTERVAL.
Типы данных CHARACTER и CHARACTER VARYING совместно называются типами данных символьных строк; типы данных BIT и BIT VARYING - типами данных битовых строк. Типы данных символьных строк и типы данных битовых строк совместно называются строчными типами данных, а значения строчных типов называются строками.
Типы данных NUMERIC, DECIMAL, INTEGER и SMALLINT совместно называются типами данных точных чисел. Типы данных FLOAT, REAL и DOUBLE PRECISION совместно называются типами данных приблизительных чисел. Типы данных точных чисел и типы данных приблизительных чисел совместно называются числовыми типами. Значения числовых типов называются числами.
Типы данных DATE, TIME и TIMESTAMP совместно называются типами даты-времени. Значения типов даты-времени называются "дата-время". Тип данных INTERVAL называется интервальным типом.
Поскольку основным способом использования языка SQL при создании прикладных информационных систем является встраивание операторов SQL в программы, написанные на традиционных языках программирования, необходимо для всех потенциально используемых языков программирования иметь правила соответствия встроенных типов SQL встроенным типам соответствующих языков. Стандарт обеспечивает такие соответствия. В частности, для языка Си установлены следующие соответствия: CHARACTER соответствует строкам Си (массивам символов, завершающимся "пустым" символом); INTEGER соответствует long; SMALLINT соответствует short; REAL соответствует float; DOUBLE PRECISION соответствует double. Естественно, это не означает, что в базах данных числа хранятся именно в той форме, в которой они представляются в Си-программе. Необходимые преобразования представлений обеспечиваются на интерфейсе прикладной программы и СУБД.
Важным понятием реляционных баз данных, зафиксированным в стандарте языка SQL, является понятие домена. Домен - это именованное множество значений некоторого встроенного типа, ограниченное условием, задаваемым при определении домена. Условие определяет вхождение значения базового типа во множество значений домена. В некотором смысле можно считать понятие домена расширением понятия ограниченного типа в языках программирования. В частности, если столбец C некоторой таблицы определен на домене D, то система гарантирует, что в этом столбце будут присутствовать только значения домена D. Кроме того, считается допустимым соединять таблицы T1 и T2 по значениям столбцов C1 и C2 только в том случае, когда C1 и C2 определены на общем домене D.
Значения всех упомянутых типов (и определенных на них доменов) имеют фиксированную или, по крайней мере, ограниченную длину. Даже для типов CHARACTER VARYING и BIT VARYING длина допустимого значения обычно ограничена размером страниц внешней памяти, используемых СУБД для хранения баз данных. В связи с потребностями современных приложений (географических, мультимедийных, категории CAD/CAM и т.д.) в большинстве СУБД поддерживается дополнительный, не специфицированный в стандарте SQL псевдотип данных с собирательным названием BLOB (Binary Large Object). Значения этого типа представляют собой последовательности байт, на которые на уровне СУБД не накладывается никакая более сложная структура и длина которых практически не ограничена (в 32-разрядных архитектурах - до 2 Гбт). Необходимая структуризация значений типа BLOB производится на прикладном уровне. Традиционные СУБД обеспечивают очень примитивный набор операций со столбцами типа BLOB - выбрать значение столбца в основную память или в файл и занести в столбец значение из основной памяти или файла.
В настоящее время отсутствует общая точка зрения относительно того, что должна обеспечивать объектно-реляционная СУБД по части обеспечения типовой среды (похоже, что до принятия следующего стандарта - SQL-3 - окончательной ясности так и не будет). Однако наличие на рынке по крайней мере трех развитых систем с объектно-реляционными расширениями дает возможность сделать небольшой предварительный обзор обязательных возможностей.
Фактически, строчный тип - это именованная спецификация одного или более столбцов (для каждого столбца указывается имя, а также его тип или домен). После определения строчного типа можно специфицировать таблицы, заголовок которых соответствует этому типу или включает его как свою часть.
Считается, что любая супертаблица включает строки всех своих подтаблиц, спроецированных на заголовок супертаблицы (кроме того, при работе с супертаблицей можно явно указать, что пользователя или прикладную программу интересуют только "собственные" строки супертаблицы). В ряде случаев использование механизма наследования таблиц с использованием семантики включения позволяет более правильно (без излишеств) спроектировать базу данных и обойтись без привлечения операторов объединения при формулировке сводных запросов.
Для каждой разновидности типа коллекции имеется предопределенный набор операций (например, доступ к элементу массива по индексу). После определения любого типа коллекции его можно использовать как любой встроенный тип. В частности, типом столбца таблицы может быть тип множества, базовым типом которого является строчный тип. Понятно, что с использованием типов коллекций можно организовывать базы данных с произвольно сложной иерархической структурой.
Позднее, в конце 1960-х годов, тот же учёный исследовал полиморфные системы типов. Позже, в 1970-х годах, Робин Милнер предложил практическую реализацию расширенной системы полимор
13 10 2014
7 стр.
В языке программирования Turbo Pascal все данные, используемые программой должны принадлежать к какому-либо типу данных. Некоторые из них
13 10 2014
1 стр.
Блеза Паскаля. На основе языка Паскаль в 1985 г фирма Borland выпустила версию Turbo Pascal версии с этого времени язык Паскаль используется во всем мире в учебных заведениях в кач
02 10 2014
4 стр.
Разработчиком языка Си++ является Бьерн Страуструп. В своей работе он опирался на опыт создателей языков Симула, Модула 2, абстрактных типов данных. Основные работы велись в исслед
10 10 2014
13 стр.
В данном докладе рассматриваются проблемы быстрого ввода данных в электронный каталог Ирбис, и пути их решения с помощью программы ms excel 2007 и кода Perl
26 09 2014
1 стр.
Синтаксис языка совокупность правил, определяющих допустимые конструкции (слова, предложения) языка, его форму
09 10 2014
2 стр.
По существу это будет определение идентификатора, который можно будет дальше использовать в коде программы в качестве имени типа наряду со стандартными типами языка Паскаль. Естест
13 10 2014
1 стр.
Исследование эффективности алгоритмов сортировок для различных структур и размерностей данных 9
11 10 2014
8 стр.