Абстрактный тип данных общие положения о данных абстрактный

Все встроенные типы данных, являются абстрактными, хотя так их называют редко.

Понятие абстракции

Абстракция - это суждение или представление о некотором объекте, которое содер­жит только свойства, являющиеся существенными в данном контексте. Абстракция по­зволяет объединять экземпляры объектов в группы, внутри которых общие свойства объектов можно не рассматривать, т.е. абстрагироваться от них. Абстракция - это эффективное средство против сложности программирования, позволяющее программисту сосредоточиться на существенных свойствах объектов. Виды абстракций: абст­ракция процесса и абстракция данных .

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

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

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

Инкапсуляция

Разделение программы на синтаксические контейнеры, ко­торые содержат группы логически связанных подпрограмм и данных. Эти синтаксические контейнеры называются модулями, а процесс их разработки- модуляризацией.

Составление программы из наборов подпрограмм и данных, каждый из ко­торых можно компилировать отдельно, без повторной компиляции остальной части про­граммы. Такой набор называется единицей компиляции.

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

Абстрактные типы данных, определяемые пользователем

Абстрактные типы данных, определяемые пользователем, должны иметь следующие свойства:

1) определение типа, позволяющее про­граммным модулям объявлять переменные этого типа, создавая при этом реальное пред­ставление этих переменных в памяти.

2) набор операций для манипуляций с объектами данного типа.

Формальное определение абстрактного типа данных в контексте типов, определенных пользователем: абстрактный тип данных - это тип данных, кото­рый удовлетворяет следующим двум условиям.

    Представление (определение типа) и операции над объектами данного типа содержатся в одной синтаксической единице, переменные данного типа можно создавать и в других модулях.

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

Упаковка представления типа и операций в отдельную син­таксическую единицу, позволяет организо­вывать программу в виде логических единиц, которые можно компилировать отдельно. Во-вторых, появляется возможность модифицировать представления объектов данного типа или операции с ними в отдельной части программы. У сокрытия деталей представ­ления типа есть преимущества. Клиенты не мо­гут "видеть" детали представления объектов, и их код не зависит от это­го представления. Таким образом, представления объектов можно изменять в любое время, не требуя при этом вносить изменения в код клиентов. Другим очевидным и важным преимуществом сокрытия информации является повы­шенная надежность. Клиенты не могут непосредственно изменять основные представле­ния объектов ни преднамеренно, ни случайно, следовательно, возрастает целостность та­ких объектов. Объекты можно изменять только с помощью предусмотренных для этого операций.

Вопросы разработки типов

Должна существовать воз­можность делать имя типа и заголовки подпрограмм видимыми в клиентах абстракции. Это позволяет клиентам объявлять переменные абстрактного типа и манипулировать их значе­ниями. Несмотря на то что имя типа должно быть видимым извне, его определение должно быть скрыто.

Существует очень мало общих встроенных операций, которые можно выполнять с объектами абстрактных типов, в отличие от операций, предусмотренных определением типа. К таким операциям относятся присваивания, а также проверки равенства и неравенства. Если язык не позво­ляет пользователям перегружать операцию присваивания, то она должна быть встроен­ной. Проверки равенства и неравенства в одних случаях должны быть заранее определе­ны, а в других - нет. Разработчик типа должен определить операции для большинства абстрактных типов данных сам.

Языки Smalltalk, C++ и Java непосредственно поддерживают абстрактные типы данных.

Абстрактные типы данных в языке C++

Языки Ada и Modula-2 обеспечивают инкапсуляцию, которая может использоваться при моделировании абстрактных типов данных, в языке C++ введено по­нятие класса, который непосредственно поддерживает абстрактные типы данных. В язы­ке C++ классы - это типы, а пакеты языка Ada и модули языка Modula-2 типами не являют­ся. Пакеты и модули импортируются, позволяя импортирующей программной единице объявлять переменные любого типа, определенного в пакете или модуле. В программе на языке C++ переменные объявляются как сущности, имеющие тип данного класса. Таким образом, классы гораздо больше похожи на встроенные типы, чем пакеты или модули. Программная единица, которая видит пакет в языке Ada или модуль в языке Modula-2, имеет доступ к любым открытым сущностям просто по их именам. Программная едини­ца на языке C++, которая объявляет экземпляр класса, также имеет доступ к любым от­крытым сущностям в этом классе, но только через экземпляр этого класса.

Абстрактный тип данных Общие положения о данных Абстрактный тип данных общие положения спецификация, представление, реализация 1

Что такое данные? Набор различных информационных объектов, над которыми выполняются те или иные действия операторами программы, называются данными. Данные - непременный атрибут любой программы. Ими могут быть: - отдельные биты; - последовательность независимых битов; -числа в разных формах представления; -байты и группы независимых байтов; -массивы чисел; -связные списки; -отдельные файлы и системы файлов. 2

Универсальное представление этого многообразия данных сложно и нецелесообразно Целесообразно разделить их на типы 3

Что такое тип данных? Тип данных определяется: – Форматом представления в памяти компьютера по определенным соглашениям алгоритмического языка, но без необходимости вычислений; – Множеством допустимых значений, которые может принимать принадлежащая к выбранному типу переменная или константа; – Множеством допустимых операций, применимых к этому типу. 4

Примеры типов данных Целочисленные типы Вещественный тип Логический тип Символьный тип Перечисляемый тип Интервальный тип Указатели 5

Целочисленные типы имеется пять предопределенных целочисленных типов: Shortint, Integer, Longint, Byte и Word. Каждый тип обозначает определенное подмножество целых чисел. Значение одного целочисленного типа может быть явным образом преобразовано к другому целочисленному типу с помощью приведения типов. 6

Вещественный тип К вещественному типу относится подмножество чисел, представляемых в формате с плавающей точкой и с фиксированным числом цифр. Запись значения в формате с плавающей запятой обычно включает три значения - m, b и e - таким образом, что m * b ^ e = n, где b всегда равен 2, а m и e являются целочисленными значениями в диапазоне вещественного типа. Эти значения m и e далее определяют диапазон представления и точность вещественного типа. Пример: 0. 143 E+22, где m - 0. 143; b=2(подразумевается), e=22. Имеется пять видов вещественных типов: вещественное (Real), с одинарной точностью (Single), с двойной точностью (Double), с повышенной точностью (Extended) и сложное (Comp). 7

Логический тип Существует 4 предопределенных логических (булевских) типа: Boolean, Byte. Bool, Word. Bool и Long. Bool. Значения булевского типа обозначаются встроенными идентификаторами констант False и True. Логические переменные могут использоваться для хранения результатов каких - либо логических вычислений. Для булевых переменных разрешены только 2 операции сравнения "="(равно) и ""(неравно). 8

Символьный тип Множеством значений этого типа являются символы, упорядоченные в соответствии с расширенным набором символов кода ASCII. Это буквы ["A". . . "Z", "a". . . "z"], цифры ["0". . . "9"], знаки препинания и специальные символы. Переменная этого типа в памяти занимает один байт. 9

Перечисляемый тип Перечислимые типы определяют упорядоченные множества значений через перечисление идентификаторов, которые обозначают эти значения. Упорядочение множеств выполняется в соответствии с последовательностью, в которой перечисляются идентификаторы. Type Week = (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday); 10

Интервальный тип Интервальный тип представляет собой диапазон значений из порядкового типа. Определение интервального типа включает наименьшее и наибольшее значение в поддиапазоне. Type Interval = 0. . . 1000; Такая декларация типа указывает компилятору, что для переменных этого типа допустимы только числа из указанного диапазона. Тем самым в программе могут быть автоматически организованы проверки корректности операций присвоения для этих переменных. 11

Общее для типов данных Каждому из типов данных соответствует множество простых операций. INTEGER-операции +, -, *, div, mod REAL - операции + , -, *, / BOOLEAN- операции - конъюнкция (и), дизъюнкция V (или), отрицание (не) CHAR-операции ORD (с) -N: (С в ASCII), CHR (I) I -тый символ в ASCII По мере возрастания объемов и сложности представления информации возникает необходимость в удобных формах ее представления, хранения и обработки. 12

Определение абстрактный тип данных (АТД или abstract data type, или ADT), - это множество абстрактных объектов, представляющих элементы данных, и определенные на нем наборы операций, которые могут быть выполнены над элементами этого множества. 13

АТД – обобщение типов данных Абстрактные типы данных (АТД) можно рассматривать как средство расширения языков программирования. Сравним абстрактный тип данных с таким знакомым понятием, как процедура. Процедуру можно рассматривать как обобщённое понятие оператора. Две характерные особенности процедур – обобщение и инкапсуляция, отлично характеризуют абстрактные типы данных. АТД можно рассматривать как обобщение простых типов данных (целых, действительных и т. д.), точно также как процедура является обобщением простых операторов (+, - и т. д.) 14

Преимущества АТД Абстрактные структуры данных предназначены для удобного хранения и доступа к информации. Они предоставляют удобный интерфейс для типичных операций с хранимыми объектами, скрывая детали реализации от пользователя. Конечно, это весьма удобно и позволяет добиться большей модульности программы. 15

Пример Для автоматизированного управления температурой в различных комнатах большого здания полезным АТД был бы ТЕРМОСТАТ. В программе может быть много переменных типа ТЕРМОСТАТ, соответствующих реальным термостатам в различных помещениях здания. АТД может быть описан своим именем, множеством значений и допустимыми операциями так же, как и любой другой тип данных. Описание для типа ТЕРМОСТАТ: – Тип данных: ТЕРМОСТАТ – Область значений: температура может изменяться в диапазоне от 0 до 50 градусов (по Цельсию). – Операции: Выше, Ниже, Установить, Проверить, Тревога. (Можно придумать много полезных операций, но слишком большое их количество ухудшает абстракцию) 16

Уровни абстракции Уровни абстракции напоминают слои программного обеспечения. Высшие уровни абстракции отражают представление пользователя о решении задачи. Нижние уровни абстракции – возможности языка программирования. 17

Пример абстракции на уровне пользователя Архитектор представляет дом в виде стен, полов, окон, дверей и т. д. В этом случае тип данных Рисунок. Двери мог бы стать хорошим абстрактным типом. Тип данных: Рисунок. Двери Операции: Рисовать. Дверь Стереть. Дверь Рисовать. Двойную. Дверь ……. Рисунок. Двери являются абстракцией высокого уровня, отражающего взгляд пользователя на проблему 18

Пример абстракции на уровне программиста Программист может предложить другой уровень абстракции для этих объектов, например, прямоугольник. Тип данных: Прямоугольник Операции: Рисовать. Прямоугольник Стереть. Прямоугольник Разделить. Прямоугольник. На. Части ……. Прямоугольник – абстракция более низкого уровня, поскольку она ближе к реализации. 19

Конструкторы АТД Каждый АТД должен содержать операции построения значений своего типа. Такие операции называются конструкторами. Конструкторов должно быть достаточно для порождения всего множества значений данного типа. АТД, удовлетворяющий этому свойству, называется полным. Неполный АТД – ошибка проектирования. 20

Рекомендации к выбору операций абстрактного типа данных Целесообразно включение следующих операций: – операции-конструкторы, – операции проверки, – операции преобразования типов, – операции ввода-вывода, – операции копирования, – операции-селекторы. Постарайтесь свести к минимуму число операций. Простой АТД легче понять. Поддерживайте связь операций с выбранной абстракцией типа. 21

Первичный конструктор Операции, создающие новые значения АТД вне зависимости от его предшествующего значения, называются первичными конструкторами. Каждый АТД включает по меньшей мере один первичный конструктор: без него невозможно сформировать начальное значение. 22

Использование скрытых типов Абстрактные типы данных лучше объявлять в виде скрытых типов. Это позволяет переместить описание структуры данных в модуль реализации, где оно преимущественно используется. Они также обеспечивают возможность предотвращения прямого доступа к компонентам типа со стороны импортера. Поскольку скрытый тип всегда реализуется с помощью указателя, то в АТД должны быть включены три операции. – Создать - операция, создающая узел соответствующей структуры. – Уничтожить - операция по освобождению памяти узла скрытого типа. – Присвоить - операция копирования полей динамической структуры узла скрытого типа. 23

Что такое спецификация и реализация у абстрактного типа данных Абстрактный тип данных - это способ определения некоторого понятия в виде класса объектов с некоторыми свойствами и операциями. В языке программирования такое определение оформляется как специальная синтаксическая конструкция, называемая в разных языках капсулой, модулем, кластером, классом, пакетом, формой и т. д. Эта конструкция в самой развитой форме содержит: спецификацию типа данных, включающую описание интерфейса (имя определяемого типа, имена операций с указанием их профилей) и абстрактное описание операций и объектов, с которыми они работают, некоторыми средствами спецификации; реализацию типа данных, включающую конкретное описание тех же операций и объектов. 24

Классификация типов данных по способу описания и защиты пакетированный, если описание типа данных собрано в одном месте (в одном пакете), т. е. его объекты и операции объединены в одно понятие; он имеет определение, которое может содержать, однако, лишь его реализацию; инкапсулированный, если тип данных пакетированный, его определение содержит описание интерфейса и реализацию, а также предусмотрена инкапсуляция реализации; абстрактный, если тип данных инкапсулированный и его спецификация включает абстрактное описание. 25

Составляющие спецификации Программирование, как процесс, начинается с постановки задачи (ее определения), или спецификации задачи. Далее повсеместно в тексте используются спецификации, состоящие из шести составляющих: – Название - название решаемой задачи; – Описание - несколько предложений, описывающих суть задачи; – Вход - детальное описание предполагаемой формы входных данных; – Выход - детальное описание предполагаемой формы выходных данных; – Ошибки - подробный список ситуаций, возникающих при неправильных входных данных; – Пример - пример выполнения в терминах вход-выход. 26

П р и м е р спецификации Абстрактный тип данных СТЕК, реализующий широко известную структуру данных, которая характеризуется тем, что в нее можно "поместить" некоторый элемент и "выбрать" из нее элемент, помещенный туда самым последним. Синтаксическая часть спецификации типа данных СТЕК имеет вид type СТЕК specification is СОЗДАТЬ: function () return (@); ВСТАВИТЬ: function (integer; @) return (@); УДАЛИТЬ: function (@) return (@); ВЕРШИНА: function (@) return (integer); ПУСТ: function (@) return (boolean); end specification; Здесь операция СОЗДАТЬ выдает в качестве результата пустой стек, ВСТАВИТЬ - стек с добавленным на "верх" его элементом, УДАЛИТЬ - стек с удаленным "верхним" элементом, ВЕРШИНА - значение "верхнего" элемента стека, ПУСТ - признак пустоты стека. Элементами стека здесь могут быть только целые числа. 27

РЕАЛИЗАЦИЯ АБСТРАКТНОГО ТИПА ДАННЫХ Реализацию удобнее делать с помощью объектноориентированных языков программирования, таких как C++ или Java, в которых абстрактные типы данных поддерживаются с помощью классов Реализация АТД включает конкретное описание объектов определяемого типа и реализацию операций этого типа. Это означает, что объекты описываются либо как данные простых типов, либо как массивы, записи или объединения. Причем используются предопределенные типы данных или АТД, определенные ранее. Реализация операций состоит в описании подпрограмм, выполняющих необходимые действия с указанными объектами. Например операции +, *, =. . и т. п, но при этом скрывается сама реализация этих операций. 28

Тип данных описывает множество объектов со схожими свойствами. Все традиционные языки программирования используют набор базовых типов данных (real, integer, string, character). Базовые типы данных подчиняются предопределенному набору операций. Например, базовый тип данных integer позволяет выполнять такие операции, как сложение, вычитание, умножение, деление.

В традиционные языки программирования включаются конструкторы типов, самым распространенным из которых является конструктор record. Например, для записи типа CUSTOMER можно определить поля данных. Запись CUSTOMER будет представлять собой новый тип данных, в котором будет храниться информация о клиенте, можно напрямую получать доступ к этой структуре данных, ссылаясь на имена полей. Над записью можно выполнять такие операции, как WRITE, READ, DELETE, UPDATE. Для базовых типов данных определить новые операции нельзя.

Как и базовые типы данных, абстрактные типы данных (ATD, abstract data types) описывают множество схожих объектов. Есть отличия ATD от традиционного типа данных:

· операции под ATD определяются пользователем;

· ATD не допускают непосредственного доступа к внутреннему представлению данных и реализации методов.

В некоторых ОО-системах (например, Smalltalk) базовые типы данных реализованы как абстрактные.

Для создания абстрактного типа данных необходимо обеспечить:

· имя типа;

· представление данных или переменные экземпляра объекта, принадлежащего ATD; каждая переменная экземпляра имеет тип данных, который может быть либо базовым типом, либо другим ATD;

· операции под ATD и ограничения реализуются с помощью методов.

Определение ATD перестраивает определение класса. В некоторых ОО-системах для различения классов и типов при ссылки на структуры данных и методы класса используется ключевое слово type, а при ссылке на набор экземпляров объекта - ключевой слово class. Тип (type) более статичное понятие, а class связан в основном со временем выполнения. Отличие ОО-класса от ОО-типа можно проиллюстрировать на примере. Предположим, имеется шаблон для конструктора. К шаблону прилагается описание его структуры, а также инструкция по его использованию. Этот шаблон и есть описание типа (type definition). Комплект сделанных с помощью шаблона реальных изделий, каждое из которых имеет уникальный номер (или OID), составляет класс (class).

ATD совместно с наследованием позволяют создавать сложные объекты. Сложный объект (complex object) формируется путем комбинации других объектов, находящихся в сложных взаимосвязях друг с другом. Пример сложного объекта можно найти в системах безопасности, где используются различные типы данных:

1. стандартные (табличные) данные о сотруднике (ФИО, Таб. № и т.д.);

2. битовая карта для хранения фотографии сотрудника;

Возможность относительно просто работать с такой сложной средой данных повышает значение ОО-систем на современном рынке баз данных.

Разработка абстрактных моделей для данных и способов обработки этих данных является важнейшим компонентом в процессе решения задач с помощью компьютера. Примеры этого мы видим и на низком уровне в повседневном программировании (например, при использовании массивов и связных списков, рассмотренных в ), и на высоком уровне при решении прикладных задач (как при решении задачи связности с помощью леса объединение-поиск в "Введение"). В настоящей лекции рассматриваются абстрактные типы данных ( abstract data type , в дальнейшем АТД), позволяющие создавать программы с использованием высокоуровневых абстракций. Абстрактные типы данных позволяют отделять абстрактные (концептуальные) преобразования, которые программы выполняют над данными, от любого конкретного представления структуры данных и любой конкретной реализации алгоритма.

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

С одной стороны, применение абстрактных конструкций освобождает от забот по их детальной реализации; с другой стороны, когда производительность программы важна, необходимо знать затраты на выполнение базовых операций. Мы используем множество базовых абстракций, встроенных в аппаратные средства компьютера и служащих основой для машинных инструкций; реализуем другие абстракции в программном обеспечении; и используем дополнительные абстракции, предоставляемые написанным ранее системным программным обеспечением. Абстрактные конструкции высокого уровня часто создаются на основе более простых конструкций. На всех уровнях действует один и тот же основной принцип: необходимо найти наиболее важные операции в программах и наиболее важные характеристики данных, а затем точно определить те и другие на абстрактном уровне и разработать эффективные конкретные механизмы для их реализации. В настоящей лекции мы рассмотрим множество примеров применения этого принципа.

Для разработки нового уровня абстракции потребуется (1) определить абстрактные объекты, с которыми необходимо манипулировать, и операции , которые должны выполняться над ними; (2) представить данные в некоторой структуре данных и реализовать операции ; (3) и (самое главное) обеспечить, чтобы эти объекты было удобно использовать для решения прикладных задач. Эти пункты применимы и к простым типам данных, так что базовые механизмы для поддержки типов данных, которые были рассмотрены в "Элементарные структуры данных" , можно адаптировать для наших целей. Однако язык C++ предлагает важное расширение механизма структур, называемое классом ( class ). Классы исключительно полезны при создании уровней абстракции и поэтому рассматриваются в качестве основного инструмента, который используется для этой цели в оставшейся части книги.

Определение 4.1. Абстрактный тип данных (АТД) - это тип данных (набор значений и совокупность операций для этих значений), доступ к которому осуществляется только через интерфейс. Программу, которая использует АТД, будем называть клиентом, а программу, содержащую спецификацию этого типа данных - реализацией.

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

В программах на языке C++ это различие обычно проводится немного четче, так как проще всего создать интерфейс , включив в него представление данных , но указав, что клиентским программам не разрешен прямой доступ к данным. Другими словами, разработчики клиентских программ могут знать представление данных , но никоим образом не могут его использовать.

В качестве примера рассмотрим интерфейс типа данных для точек ( программа 3.3) из раздела 3.1 "Элементарные структуры данных" . В этом интерфейсе явно объявляется, что точки представлены как структуры, состоящие из пары чисел с плавающей точкой, обозначаемых x и у. Подобное применение типов данных является обычным в больших системах программного обеспечения: мы разрабатываем набор соглашений о представлении данных (а также определяем ряд связанных с ними операций) и делаем эти правила доступными через интерфейс , чтобы ими могли пользоваться клиентские программы, входящие в состав большой системы. Тип данных обеспечивает согласованность всех частей системы с представлением основных общесистемных структур данных. Какой бы хорошей такая стратегия ни была, она имеет один изъян: если необходимо изменить представление данных , то потребуется изменить и все клиентские программы. Программа 3.3 снова дает нам простой пример: одна из причин разработки этого типа данных - удобство работы клиентских программ с точками, и мы ожидаем, что в случае необходимости у клиентов будет доступ к отдельным координатам точки. Но мы не можем перейти к другому представлению данных (скажем, к полярным координатам, или трехмерным координатам, или даже к другим типам данных для отдельных координат) без изменения всех клиентских программ.

В отличие от этого, программа 4.1 содержит реализацию абстрактного типа данных, соответствующего типу данных из программы 3.3, но с использованием класса языка C++, в котором сразу определены как данные, так и связанные с ними операции . Программа 4.2 является клиентской программой, работающей с этим типом данных. Эти две программы выполняют те же самые вычисления, что и программы 3.3 и 3.8. Они иллюстрируют ряд основных свойств классов, которые мы сейчас рассмотрим.

Когда мы пишем в программе определение наподобие int i, мы указываем системе зарезервировать область памяти для данных (встроенного) типа int , к которой можно обращаться по имени i. В языке C++ для подобных сущностей имеется термин объект . При записи в программе такого определения, как POINT p, говорят, что создается объект класса POINT , к которому можно обращаться по имени p. В нашем примере каждый объект содержит два элемента данных, с именами x и у. Как и в случае структур, к ним можно обращаться по именам вроде p.y.

Элементы данных x и у называются данными-членами класса. В классе могут быть также определены функции-члены, которые реализуют операции , связанные с этим типом данных. Например, класс , определенный в программе 4.1, имеет две функции-члена с именами POINT и distance .

Клиентские программы, такие как программа 4.2, могут вызывать функции-члены, связанные с объектом, указывая их имена точно так же, как и имена данных, находящихся в какой-нибудь структуре struct. Например, выражение p.distance(q) вычисляет расстояние между точками p и q (такое же расстояние должен возвращать и вызов q.distance(p) ). Функция POINT() - первая функция в программе 4.1 - является особой функцией-членом, называемой конструктором: у нее такое же имя, как и у класса, и она вызывается тогда, когда требуется создать объект этого класса.

Программа 4.1. Реализация класса POINT (точка)

В этом классе определен тип данных , который состоит из набора значений, представляющих собой "пары чисел с плавающей точкой" (предполагается, что они интерпретируются как точки на декартовой плоскости), а также две функции-члена, определенные для всех экземпляров класса POINT : функция POINT() , которая является конструктором, инициализирующим координаты случайными значениями от 0 до 1, и функция distance(POINT) , вычисляющая расстояние до другой точки. Представление данных является приватным ( private ), и обращаться к нему или модифицировать его могут только функции-члены. Сами функции-члены являются общедоступными ( public ) и доступны для любого клиента. Код можно сохранить, например, в файле с именем POINT .cxx.

#include class POINT { private: float x, у; public: POINT() { x = 1.0*rand()/RAND_MAX; у = 1.0*rand()/RAND_MAX; } float distance(POINT a) { float dx = x-a.x, dy = y-a.y; return sqrt(dx*dx + dy*dy); } };

Программа 4.2. Программа-клиент для класса POINT (нахождение ближайшей точки)

Эта версия программы 3.8 является клиентом, который использует АТД POINT , определенный в программе 4.3. Операция new создает массив объектов POINT (вызывая конструктор POINT () для инициализации каждого объекта случайными значениями координат). Выражение a[i].distance(a[j]) вызывает для объекта a[i] функцию-член distance с аргументом a[j] .

#include #include #include "POINT.cxx" int main(int argc, char *argv) { float d = atof(argv); int i, cnt = 0, N = atoi(argv); POINT *a = new POINT[N]; for (i = 0; i < N; i++) for (int j = i+1; j < N; j++) if (a[i].distance(a[j]) < d) cnt+ + ; cout << cnt << " пар в радиусе " << d << endl; }

Определение POINT p в программе-клиенте приводит к выделению области памяти под новый объект и затем (с помощью функции POINT() ) к присвоению каждому из двух его элементов данных случайного значения в диапазоне от 0 до 1.

Этот стиль программирования, который иногда называется объектно-ориентированным программированием, полностью поддерживается конструкцией class языка C++. Класс можно считать расширением понятия структуры, где не только объединяются данные, но и определяются операции с этими данными. Может существовать много разных объектов, принадлежащих одному классу, но все они подобны в том, что их данные-члены могут принимать один и тот же набор значений, и с этими данными-чле-нами может выполняться одна и та же совокупность операций - в общем, это экземпляры одного и того же типа данных. В объектно-ориентированном программировании объекты предназначены для обработки своих данных-членов (в отличие от использования независимых функций для обработки данных, хранимых в объектах).

Мы рассматриваем описанный выше пример небольшого класса просто чтобы познакомиться с основными чертами классов; поэтому он далеко не полон. В реальном коде для класса точки у нас будет намного больше операций. Например, в программе 4.1 отсутствуют даже операции , позволяющие узнавать значения координат x и y . Как мы увидим, добавление этих и других операций - довольно простая задача. В части 5 мы более подробно рассмотрим классы для точки и других геометрических абстракций, например, линий и многоугольников.

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

Доброго времени суток, хабравчане!

Следующий пост является изложением моих размышлений на тему природы классов и АТД. Эти размышления дополнены интересными цитатами из книг гуру разработки программного обеспечения

Введение

Начнем с того, что плавно подойдем к определению АТД. АТД, в первую очередь, представляет собой тип данных, что означет следущее:
наличие определенных доступных операций над элементами этого типа;
а также данные, относительно которых эти операции выполняются (диапазон значений).

Что же означает слово “абстрактный”? В первую очередь понятие “абстрактность” означет сосредоточение внимания на чем-то важном и, при этом, нам нужно отвлечься от неважных, на данный момент, деталей. Определение абстрактности хорошо раскрыто в книге Гради Буча (“Grady Booch”). Звучит определение так:

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

Итак, что же будет, если слить понятия “тип данных” и “абстракция” воедино? Мы получим тип данных, который предоставляет нам некий набор операций, обеспечивающих поведение объектов этого типа данных, а также этот тип данных будет скрывать те данные, с помощью которых реализовано данное поведение. Отсюда, приходим к понятию АТД:

АТД – это такой тип данных, который скрывает свою внутреннюю реализацию от клиентов.
Удивительно то, что путем применения абстракции АТД позволяет нам не задумываться над низкоуровневыми деталями реализации, а работать с высокоуровневой сущностью реального мира (Стив Макконнелл).

Я считаю, что при разработке АТД сначала нужно определить интерфейс, так как интерфейс не должен зависеть от внутреннего представления данных в АТД. После определения операций, сотставляющих интерфейс, нужно сосредоточиться на данных, которые и будут реализовать заданное поведение АТД. В итоге мы получим некую структуру данных – механизм позволяющий хранить и обрабатывать данные. При этом, прелесть АТД в том, что если нам захочется изменить внутренне представление данных, то нам не придется блуждать по всей программе и менять каждую строку кода, которая зависит от данных, которые мы хотим поменять. АТД инкапсулирует эти данные, что позволяет менять работу объектов этого типа, а не всей программы.

Преимущества АТД

Использование АТД имеет массу преимуществ (все описанные преимущества можно найти в книге Стива Макконнелла «Совершенный код”):

  • Инкапсуляция деталей реализации.
    Это означает, что единожды инкапсулировав детали реализации работы АТД мы предоставляем клиенту интерфейс, при помощи которого он может взаимодействовать с АТД. Изменив детали реализации, представление клиентов о работе АТД не изменится.
  • Снижение сложности.
    Путем абстрагирования от деталей реализации, мы сосредатачиваемся на интерфейсе, т.е на том, что может делать АТД, а не на том как это делается. Более того, АТД позволяет нам работать с сущностью реального мира.
  • Ограничение области использования данных.
    Используя АТД мы можем быть уверены, что данные, представляющие внутреннюю структуру АТД не будут зависеть от других участков кода. При этом реализуется “независимость” АТД.
  • Высокая информативность интерфейса.
    АТД позволяет представить весь интерфес в терминах сущностей предметной области, что, согласитесь, повышает удобочитаемость и информативность интерфейса.

Стив Макконнелл рекомендует представлять в виде АТД низкоуровнеые типы данных, такие как стек или список. Спросите себя, что представляет собой этот список. Если он представляет список сотрудников банка, то и рассматривайте АТД как список сотрудников банка.

Итак, мы разобрались, что такое АТД и назвали преимущества его применения. Теперь стоит отметить, что при разработке классов в ООП следует думать, в первую очередь, об АТД. При этом, как сказал Стив МакКоннелл, Вы программируете не на языке, а с помощью языка. Т.е Вы будете программировать выходя за рамки языка, не ограничиваясь мыслями в терминах массивов или простых типов данных. Вместо этого Вы будете думать на высоком уровне абстракции (например, в терминах электронных таблицах или списков сотрудников). Класс – это не что иное как дополнение и способ реализации концепции АТД. Мы можем даже представить класс в виде формулы:
Класс = АТД + Наследование + Полиморфизм.
Так почему же следут думать об АТД, при разработке классов. Потому что, сперва мы должны решить какие операции будут составлять интерфейс будущего класса, какие данные скрыть, а к каким предоставить открытый доступ. Мы должны подумать об обеспечении высокой информативности интерфейса, легкости оптимизации и проверки кода, а также о том, как бы нам предоставить правильную абстракцию, чтобы можно было думать о сущностях реального мира, а не о низкоуровнеых деталях реализации. Я считаю, что именно после определения АТД мы должны думать о вопросах наследования и полиморфизма.

Стоит отметить, что концепция АТД нашла гирокое применение в ООП, т.к именно эта концепция дополняет ООП и позволяет уменшить сложность программ в быстроменяющемся мире требований к ПО.

Данную статью я писал для того, что бы обратить внимание разработчиков на АТД с целью повышения качества работы и разработки программного обеспечения.

Использованные источники:

Стив Макконнелл – “Совершенный код”;
Роберт Седжвик – «Алгоритмы на Java».



Есть вопросы?

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: