ООП. Объектно-ориентированное программирование, Объекты |
ООП. Объектно-ориентированное программирование, Объекты |
Altair |
15.05.2004 19:31
Сообщение
#1
|
Ищущий истину Группа: Модераторы Сообщений: 4 824 Пол: Мужской Реальное имя: Олег Репутация: 45 |
Один из подходов в программировании носит название: "Объектно-ориентированное программирование" или, сокращенно, ООП. Идея этого подхода заключается в стремлении связать данные с обрабатывающими эти данные процедурами в единое целое - ОБЪЕКТ.
В Турбо Паскале ООП реализовано начиная с версии 5.5. ООП основано на трех важных принципах, придающих объектам особые свойства и отличающих их от других типов данных. Рассмотрим их:
Сначала может показаться, что при описании нет разницы между объектами и записями. На деле разница заключается в том, что при описании объекта в него могут входить заголовки процедур и функций, ведь по определению объект это "Данные+Алгоритмы". Перефразируя Вирта, можно сказать что: "Алгоритмы+Структуры Данных=Объекты". Выглядит описание объекта так: type Переменные, описанные в объекте называются полями, а процедуры их обработки - методами. В самом типе объекта описан лишь интерфейс метода (так же, как при написании модуля в разделе INTERFACE мы описываем только заголовки), т.е. способ его вызова. Сам метод описывается в разделе процедур и функций, и заголовок имеет нестандартную форму (перед его именем обязательно указывается имя типа объекта, к которому этот метод принадлежит): procedure ObjectType.ProcedureName(...); Т.е <имя_объекта>.<имя_процедуры> Параметры описываются как обычно, за исключением того, что внутри метода всегда доступны поля объекта непосредственно по их именам. Например: type Так как задание заголовка метода в описании типа объекта является опережающим описанием, то так же, как при реализации процедур и функций в разделе IMPLEMENTATION, список параметров может опускаться, то есть, такое описание будет полностью аналогично предыдущему: procedure TA.give; Переменные типа "объект" можно создавать как обычно, объявлением в списке переменных (при таком способе для использования экземпляров объектов - переменных объектного типа - в программе, их вызывают так: <имя_объекта>.<имя_метода>): type TA = object ... end; но большее распространение получил метод их размещения в динамической памяти. Для этого нужно создать дополнительный тип - указатель на объект (в таком случае для обращения к полям или методам объекта указатель надо разыменовать): type Наследование При описании объекта-наследника (также называемого производным типом), имя его родителя указывается в скобках. Например: TA = Поля и методы родителя могут появляться в реализации методов наследника, как если бы они были описаны явно в самом наследнике. Процесс наследования является транзитивным: если TB наследуется от TA, а TC в свою очередь - наследник TB, то тип TC также считается наследником TA. Следует обратить внимание на то, что при наследовании полей в производном типе нельзя объявлять идентификаторы, которые уже использовались в одном их типов-родителей. (На методы это ограничение не распространяется, в случае повторного определения метода он считается переопределенным, и ко всем потомкам будет переходить именно переопределенный метод.) Из "умения" объектов "наследовать" вытекает правило присваивания для переменных типа "Объект": переменным такого типа можно присваивать не только значения этого же типа, но и значения любого производного типа. Например, при таком определении: type для копирования значения X записанного в переменной b в переменную a достаточно выполнить присваивание: a := b; Внимание: Операция присваивания возможна только таким путем: "Родитель <-- Наследник" При этом гарантируется заполнение всех полей типа "Родитель" содержимым соответствующих полей типа "Наследник", так как в "Наследнике" число полей не меньше, чем в родителе. В противном случае могла бы возникнуть неопределенность с "лишними" полями, которых нет в "Родителе". Операцией присваивания копируются только поля. Методы таким образом не присваиваются... Использование объектов Посмотрим теперь на практике, как работать с объектами. uses crt; Итак, рассмотрим эту программу. Это первая наша программа с объектами. В ней есть 2 объекта - родитель Т1 и потомок Т2. Я специально сделал так, чтобы в них были методы (процедуры) с одинаковыми именами. Обратите внимание, что мы не описывали в Т2 процедуру Vec, однако, при вызове: c.Vec метод заработал. Это произошло, потому что объект T2 является потомком Т1, и он знает все методы и данные своего родителя Т1. И наоборот Т1 не знает, что есть процедура Summ. На этом примере мы также убедились, что при перекрытии работает тот метод, который был описан позднее (т.е. метод потомка, а не родителя). То есть при вызове C.Print пошла запись в файл, а не на экран монитора, как есть в методе родителя. Таким образом, при наследовании объект-потомок наследует все методы родителя и перекрывает одноименные. |
volvo |
29.03.2005 21:53
Сообщение
#2
|
Гость |
Динамические объектные типы
Переменные объектного типа могут быть статичекими или динамическими, т.е. располагаться в сегменте данных (статические) или в куче (динамические). Перепишем нашу программу, используя динамические объекты. uses crt; Инициализация динамической переменной B реализуется с помощью функции New. В этом случае первым параметром указывается имя типа инициализируемой переменной, а вторым осуществляется вызов метода-конструктора. Такой прием характерен для техники ООП. При этом распределение объектов в динамической памяти происходит одновременно с инициализацией ТВМ. Обработка ошибок при работе с объектами При использовании динамических объектов вероятна ситуация, когда для размещения экземпляра объекта не хватает памяти. Чтобы корректно обработать эту ситуацию, можно использовать процедуру Fail, которая отменяет все проделанные до данного момента определения, и освобождает экземпляр, размещенный в памяти... При этом ссылка на экземпляр объекта становится равной nil. { Динамический объект } Также нехватка памяти может произойти при использовании статических объектов с полями, размещаемыми в динамической памяти. В этом случае при вызове Fail передать nil в ссылку невозможно (объект-то статический), и выходом является использование самого имени конструктора как логической функции: { Статический объект } Функция TypeOf Часто возникает ситуация, когда необходимо проверить фактический тип экземпляра объекта. Для этого используется функция: TypeOf(ИмяЭкземпляра_или_ИмяТипа): Pointer, которая возвращает указатель на таблицу VMT для этого экземпляра или типа объекта... Параметром, передаваемым в функцию должен быть экземпляр или тип, имеющий VMT, иначе произойдет ошибка. Проверить фактический тип параметра можно, например, так: type Стартовые значения для объектов Точно так же, как массивам и записям (Record), задавать начальные значения можно и статическим объектам. Для этого используется тот же синтаксис, что и при инициализации записей (начальные значения задаются только для полей? для методов стариовых значений просто не существует):
Обратите внимание, что после такого методе инициализации можно обращаться к виртуальным методам без предварительного вызова конструктора (только для экземпляра, инициализированного через Const !!!), так как компилятор автоматически обрабатывает инициализацию и создает VMT. Используя типизированные константы, можно инициализировать поля других объектов. Для этого достаточно ввести дополнительный метод: Type a = object где Self - параметр, который передается в каждый вызываемый метод объекта, и в большинстве случаев обрабатывается компилятором автоматически (кроме случаев, когда идентификаторы начинают "конфликтовать" в пределах одного метода) Структура VMT (подготовлено BlackShadow) Структура VMT (Таблица виртуальных методов):
Структура DMT (Таблица динамических методов):
Из структуры таблицы ясно видно (из документации не менее ясно), что все методы вызываются как Far вне зависимости от {$F...} Раскажу ещё как какой метод можно вызвать. Статический:
Виртуальный:
Динамический:
И пусть этот Dispatch сам себе мозги компостирует и ищет чего там вызвать надо. |
Текстовая версия | 29.04.2024 14:52 |