Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву
Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Наследование(в делфи используют одиночное наследование)что такое и как используетсяСодержание книги
Поиск на нашем сайте Чтобы наиболее эффективно повторно использовать ранее созданные классы, одного сочетания данных и методов в единой структуре недостаточно. Например, автомо- биль может быть легковым и грузовым, и соответствующие классы будут иметь как общие поля и методы, так и отличия (например, дополнительное свойство ≪гру- зовой кузов* и связанный с ним метод ≪разгрузить≫). Однако полностью заново определять новый тип данных, если требуется изменить или добавить несколько новых свойств к старому типу, нерационально. Это плохо еще и потому, что если в Клоссы и обьекты 85 метод, имеющийся в обоих классах, потребуется внести исправления, то их при- дется делать дважды, в двух одинаковых копиях подпрограмм. Чтобы избежать ненужной работы, в объектном программировании был введен принцип наследования свойств и методов. Программисту достаточно описать один базовый класс (например, ≪автомобиль*), а классы ≪легковой автомобиль≫ и ≪гру- зовой автомобиль* основывать на этом базовом классе. При этом будут наследо- ваться все поля, свойства и методы базового (или родительского) класса, а допол- нительно описывать их не требуется. Цепочки наследования могут быть неограниченной длины. Так, у класса ≪грузовой автомобиль≫ могут быть классы-наследники (или дочерние классы) ≪МАЗ* и ≪КА- МАЗ≫, обладающие дополнительными специфическими свойствами и методами (это классы, а не объекты; объектом будет конкретный грузовик МАЗ, а не марка этого автомобиля), у класса ≪кнопка* наследники — ≪графическая кнопка*, ≪круглая кнопка≫ и так далее. При этом различные методы для каждого из наслед- ников разрешается переопределять. Например, метод ≪двигаться≫ для классов ≪МАЗ≫ и ≪КАМАЗ≫ будет, хоть и немного, но отличаться: по-разному расходуется горючее (снижается значение соответствующего свойства), по-разному набирается скорость и так далее. 3.7. Наследование 3.7.1. Понятие наследования Классы инкапсулируют (т.е. включают в себя) поля, методы и свойства; это их первая черта. Следующая не менее важная черта классов — способность наследовать поля, методы и свойства других классов. Чтобы пояснить сущность наследования обратимся к примеру с читателем текстовых файлов в формате "delimited text". Класс TDelimitedReader описывает объекты для чтения из текстового файла элементов, разделенных некоторым символом. Он не пригоден для чтения элементов, хранящихся в другом формате, например в формате с фиксированным количеством символов для каждого элемента. Для этого необходим другой класс:
Поля, свойства и методы класса TFixedReader практически полностью аналогичны тем, что определены в классе TDelimitedReader. Отличие состоит в отсутствии свойства Delimiter, наличии поля FItemWidths (для хранения размеров элементов), другой реализации метода ParseLine и немного отличающемся конструкторе. Если в будущем появится класс для чтения элементов из файла еще одного формата (например, зашифрованного текста), то придется снова определять общие для всех классов поля, методы и свойства. Чтобы избавиться от дублирования общих атрибутов (полей, свойств и методов) при определении новых классов, воспользуемся механизмом наследования. Прежде всего, выделим в отдельный класс TTextReader общие атрибуты всех классов, предназначенных для чтения элементов из текстовых файлов. Реализация методов TTextReader, кроме метода ParseLine, полностью идентична реализации TDelimitedReader, приведенной в предыдущем разделе.
При реализации класса TTextReader ничего не известно о том, как хранятся элементы в считываемых строках, поэтому метод ParseLine ничего не делает. Очевидно, что создавать объекты класса TTextReader не имеет смысла. Для чего тогда нужен класс TTextReader? Ответ: чтобы на его основе определить (породить) два других класса — TDelimitedReader и TFixedReader, предназначенных для чтения данных в конкретных форматах:
Классы TDelimitedReader и TFixedReader определены как наследники TTextReader (об этом говорит имя в скобках после слова class). Они автоматически включают в себя все описания, сделанные в классе TTextReader и добавляют к ним некоторые новые. В результате формируется дерево классов, показанное на рисунке 3.1 (оно всегда рисуется перевернутым).
Класс, который наследует атрибуты другого класса, называется порожденным классом или потомком. Соответственно класс, от которого происходит наследование, выступает в роли базового, или предка. В нашем примере класс TDelimitedReader является прямым потомком класса TTextReader. Если от TDelimitedReader породить новый класс, то он тоже будет потомком класса TTextReader, но уже не прямым. Очень важно, что в отношениях наследования любой класс может иметь только одного непосредственного предка и сколь угодно много потомков. Поэтому все связанные отношением наследования классы образуют иерархию. Примером иерархии классов является библиотека VCL; с ее помощью в среде Delphi обеспечивается разработка GUI-приложений. 3.7.2. Прародитель всех классов В языке Delphi существует предопределенный класс TObject, который служит неявным предком тех классов, для которых предок не указан. Это означает, что объявление
эквивалентно следующему:
Класс TObject выступает корнем любой иерархии классов. Он содержит ряд методов, которые по наследству передаются всем остальным классам. Среди них конструктор Create, деструктор Destroy, метод Free и некоторые другие методы. Таким образом, полное дерево классов для чтения элементов из текстового файла в различных форматах выглядит так, как показано на рисунке 3.2.
Поскольку класс TObject является предком для всех других классов (в том числе и для ваших собственных), то не лишним будет кратко ознакомиться с его методами:
Некоторые конструкции этого описания будут вам непонятны, поскольку мы их еще не изучали. Сейчас это не важно. Снова вернитесь к этому описанию после прочтения всей главы. Краткое описание методов в классе TObject: Create — стандартный конструктор. Free — уничтожает объект: вызывает стандартный деструктор Destroy, если значение псевдопеременной Self не равно nil. InitInstance (Instance: Pointer): TObject — при создании объекта инициализирует нулями выделенную память. На практике нет необходимости вызывать этот метод явно. CleanupInstance — освобождает память, занимаемую полями с типом string, Variant, динамический массив и интерфейс. На практике нет необходимости вызывать этот метод явно. ClassType: TClass — возвращает описатель класса (метакласс). ClassName: ShortString — возвращает имя класса. ClassNameIs (const Name: string): Boolean — проверяет, является ли заданная строка именем класса. ClassParent: TClass — возвращает описатель базового класса. ClassInfo: Pointer — возвращает указатель на соответствующую классу таблицу RTTI (от англ. Runtime Type Information). Таблица RTTI используется для проверки типов данных на этапе выполнения программы. InstanceSize: Longint — возвращает количество байт, необходимых для хранения в памяти одного объекта соответствующего класса. Заметим, что значение, возвращаемое этим методом и значение, возвращаемое функцией SizeOf при передаче ей в качестве аргумента объектной переменной — это разные значения. Функция SizeOf всегда возвращает значение 4 (SizeOf(Pointer)), поскольку объектная переменная — это ни что иное, как ссылка на данные объекта в памяти. Значение InstanceSize — это размер этих данных, а не размер объектной переменной. InheritsFrom (AClass: TClass): Boolean — проверяет, является ли класс AClass базовым классом. MethodAddress (const Name: ShortString): Pointer — возвращает адрес published-метода, имя которого задается параметром Name. MethodName (Address: Pointer): ShortString — возвращает имя published-метода по заданному адресу. FieldAddress (const Name: ShortString): Pointer — возвращает адрес published-поля, имя которого задается параметром Name. GetInterface (const IID: TGUID; out Obj): Boolean — возвращает ссылку на интерфейс через параметр Obj; идентификатор интерфейса задается параметром IID. (Интерфейсы рассмотрены в главе 6) GetInterfaceEntry (const IID: TGUID): PInterfaceEntry — возвращает информацию об интерфейсе, который реализуется классом. Идентификатор интерфейса задается параметром IID. GetInterfaceTable: PInterfaceTable — возвращает указатель на таблицу с информацией обо всех интерфейсах, реализуемых классом. AfterConstruction — автоматически вызывается после создания объекта. Метод не предназначен для явного вызова из программы. Используется для того, чтобы выполнить определенные действия уже после создания объекта (для этого его необходимо переопределить в производных классах). BeforeDestruction — автоматически вызывается перед уничтожением объекта. Метод не предназначен для явного вызова из программы. Используется для того, чтобы выполнить определенные действия непосредственно перед уничтожением объекта (для этого его необходимо переопределить в производных классах). Dispatch (var Message) — служит для вызова методов, объявленных с ключевым словом message. DefaultHandler (var Message) — вызывается методом Dispatch в том случае, если метод, соответствующий сообщению Message, не был найден. NewInstance: TObject — вызывается при создании объекта для выделения динамической памяти, чтобы разместить в ней данные объекта. Метод вызывается автоматически, поэтому нет необходимости вызывать его явно. FreeInstance — вызывается при уничтожении объекта для освобождения занятой объектом динамической памяти. Метод вызывается автоматически, поэтому нет необходимости вызывать его явно. Destroy — стандартный деструктор. 3.7.3. Перекрытие атрибутов в наследниках В механизме наследования можно условно выделить три основных момента:
Любой порожденный класс наследует от родительского все поля данных, поэтому классы TDelimitedReader и TFixedReader автоматически содержат поля FFile, FActive и FItems, объявленные в классе TTextReader. Доступ к полям предка осуществляется по имени, как если бы они были определены в потомке. В потомках можно определять новые поля, но их имена должны отличаться от имен полей предка. Наследование свойств и методов имеет свои особенности. Свойство базового класса можно перекрыть (от англ. override) в производном классе, например чтобы добавить ему новый атрибут доступа или связать с другим полем или методом. Метод базового класса тоже можно перекрыть в производном классе, например чтобы изменить логику его работы. Обратимся к классам TDelimitedReader и TFixedReader. В них методы PutItem, GetItem, SetActive и GetEndOfFile унаследованы от TTextReader, поскольку логика их работы не зависит от того, в каком формате хранятся данные в файле. А вот метод ParseLine перекрыт, так как способ разбора строк зависит от формата данных:
В классах TDelimitedReader и TFixedReader перекрыт еще и конструктор Create. Это необходимо для инициализации специфических полей этих классов (поля FDelimiter в классе TDelimitedReader и поля FItemWidths в классе TFixedReader):
Как видно из примера, в наследнике можно вызвать перекрытый метод предка, указав перед именем метода зарезервированное слово inherited. Когда метод предка полностью совпадает с методом потомка по формату заголовка, то можно использовать более короткую запись. Воспользуемся ей и перепишем деструктор в классе TTextReader правильно:
Два последних примера демонстрируют важный принцип реализации конструкторов и деструкторов. В конструкторах сначала вызывается конструктор предка, а затем инициализируются дополнительные поля данных. В деструкторах применяется обратная последовательность действий: сначала разрушаются данные, недоступные предку, а затем вызывается унаследованный деструктор. Всегда пользуйтесь этими правилами в своих программах, чтобы избежать ошибок.
23. Основные принципы ООП и их поддержка в Object Pascal. (в лекциях есть.)как это все поддерживается в обджект паскаль
|
||||||||||||||||||||
|
Последнее изменение этой страницы: 2017-02-21; просмотров: 452; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 216.73.217.21 (0.01 с.) |