Скачиваний:
51
Добавлен:
16.03.2015
Размер:
921.44 Кб
Скачать

Объектно-ориентированное программированиe на языке Object

Pascal

Введение

Язык программирования Object Pascal и его достойный преемник, среда программирования Delphi, построены на основе получившей широкое развитие на стыке 70 - 80-х годов 20 века теории объектно-ориентированного программирования. В то время идея описания программ в базисе логических сущностей и взаимодействия между ними не была такой уж бесспорной, а у некоторых оппонентов даже вызывала определённое недоумение. Преимущества ООП по сравнению с традиционными способами программирования:

1.Эта концепция в наибольшей степени соответствует внутренней логике функционирования операционной системы Windows. Программа, состоящая из отдельных объектов, отлично приспособлена к реагированию на события, происходящие в операционной системе.

2.Большая надёжность кода и возможность повторного использования отработанных объектов.

Объект и класс

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

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

Объект не может возникнуть из воздуха, среда программирования какимто образом должна быть проинформирована о его характеристиках. Поэтому предварительно программист описывает объект; такое описание называется классом. Класс - это чертёж будущего объекта, в котором учитываются не только его конструктивные элементы (поля), но и определяются способы управления этими элементами - методы класса.

Определение класса начинается с ключевого слова type глобального блока, за которым следуют имя класса, его поля и методы. Завершается описание директивой end. В объявление класса могут входить другие классы; таким образом можно создавать сложные составные объекты. По форме объявления классы похожи на обычные записи, но помимо полей данных могут содержать объявления пользовательских процедур и функций (методы). Пример:

type TPeople = class

Name: string;

Family: string;

procedure GetName;

procedure GetFamily;

end;

Класс содержит поля (Name, Family) и методы (GetName, GetFamily).

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

Чтобы от описания класса перейти к объекту, следует выполнить следующее объявление в секции var:

var People: TPeople;

При работе с обычными типами данных этого объявления было бы достаточно для получения экземпляра типа. Однако объекты среды Delphi являются динамическими данными, то есть распределяются в динамической памяти. Поэтому переменная People - это просто ссылка на экземпляр (объект в памяти), которого физически ещё не существует. Чтобы сконструировать объект (выделить память для экземпляра) класса TPeople и связать с ним переменную People, нужно в тексте программы поместить следующий оператор:

People := TPeople.Create; //Выделение памяти под объект

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

People.GetName;

People.GetFamily;

Кроме того, как и при работе с записями, допустимо использование оператора with, например:

with People do

GetFamily;

GetName;

Если объект становится ненужным, он должен быть удалён вызова специального метода Destroy, например:

People.Destroy; //Освобождение памяти, занимаемой объектом

Destroy - это так называемый деструктор объекта; он присутствует в классе наряду с конструктором и служит для удаления объекта из динамической памяти. После вызова деструктора переменная People становится несвязанной и не должна использоваться для доступа к полям и методам уже несуществующего объекта. Чтобы отличать в программе связанные объектные переменные от несвязанных, последнее следует инициализировать значением nil. Пример:

People := nil;

if People <> nil then People.Destroy;

Вызов деструктора для несуществующих объектов недопустим и при выполнении программы приведёт к ошибке. Чтобы избавить программистов от лишних ошибок, в объекты ввели предоставленный метод Free, который следует вызвать вместо деструктора. Метод Free сам вызывает деструктор Destroy, но только в том случае, если значение объектной переменной не равно nil. Поэтому последнюю строчку в приведённом выше примере можно переписать следующим образом:

People.Free;

После уничтожения объекта переменная People сохраняет своё значение, продолжая ссылаться на место в памяти, где объекта уже нет. Если эту переменную предполагается ещё использовать, то желательно присвоить ей значение nil, чтобы программа могла проверить, существует объект или нет. Таким образом, наиболее правильная последовательность действий при уничтожении объекта должна быть следующая:

People. Free;

People := nil;

С помощью стандартной процедуры FreeAndNil это можно сделать проще и элегантнее:

FreeAndNil(People); //Эквивалентно: People. Free; People := nil;

Значение одной объектной переменной можно присвоить другой. При этом объект не копируется в памяти, а вторая переменная просто связывается с тем же объектом, что и первая:

var People1, People2: TPeople;

begin

People1 := TPeople.Create;

People1 := People2;

People. Free;

end;

Объекты могут выступать в программе не только в качестве переменных, но также элементов массивов, полей записей, параметров процедур и функций. Кроме того, они могут служить полями других объектов. Во всех этих случаях программист фактически оперирует указателями на экземпляры объектов в динамической памяти. Следовательно, объекты изначально приспособлены для создания сложных динамических структур данных, таких как списки и деревья. Указатели на объекты для этого не нужны.

В некоторых случаях требуется, чтобы объекты разных классов содержали ссылки друг на друга. Возникает проблема: объявление первого класса будет содержать ссылку на ещё не определённый класс. Она решается с помощью упреждающего объявления:

type TPeople = class // Упреждающее объявление класса

TPeople

THuman = class

Name: TPeople;

...

end;

type TPeople = class // Упреждающее объявление класса

TPeople

People: array of THuman;

...

end;

Первое объявление класса TPeople называется упреждающим. Оно необходимо для того, чтобы компилятор нормально воспринял объявление поля Name в классе THuman.

Конструкторы и деструкторы

Особой разновидностью методов являются конструкторы и деструкторы. Создание объекта включает выделение памяти под экземпляр и инициализацию его полей, а разрушение - очистку полей и освобождение памяти. Действия по инициализации и очистке полей специфичны для каждого конкретного класса объектов. По этой причине язык Delphi позволяет переопределить стандартный конструктор Create и стандартный деструктор Destroy для выполнения любых полезных действий. Можно даже определить несколько конструкторов и деструкторов (имена им назначает сам программист), чтобы обеспечить различные процедуры создания и разрушения объектов.

Объявление конструкторов и деструкторов похоже на объявление обычных методов с той лишь разницей, что вместо зарезервированных слов function и procedure используются слова constructor и destructor. Пример:

type TPeople = class Name: string; Family: string; procedure GetName;

procedure GetFamily; construcor Create; destrucot Destroy; end;

Возможная реализация:

procedure TPeople.Create;

begin

TPeople.Name := ' ';

TPeople.Family := ' ';

end;

procedure TPeople.Destroy;

begin

//Пока ничего не делаем

end;

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

People := TPeople.Create;

то выполняется следующая последовательность действий:

1.В динамической памяти выделяется место для нового объекта.

2.Выделенная память заполняется нулями. В результате все числовые поля

иполя порядкового типа приобретают нулевые значения, строковые поля становятся пустыми, а поля, содержащие указатели и объекты получают значение nil.

3.Затем выполняются заданные программистом действия конструктора.

4.Ссылка на созданный объект возвращается в качестве значения конструктора. Тип возвращаемого значения совпадает с типом класса, использованного при вызове (в нашем примере это тип TPeople).

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

People.Create;

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

Деструктор уничтожает объект к которому применяется:

People.Destroy;

В результате выполняются:

1. Заданный программистом код завершения.

2. Освобождается занимаемая объектом динамическая память.

В теле деструктора обычно должны уничтожаться встроенные объекты и динамические данные, как правило, созданные конструктором. Как и обычные методы, деструктор может иметь параметры, но эта возможность используется крайне редко.

Методы

Процедуры и функции, предназначенные для выполнения над объектами действий, называются методами. Предварительное объявление методов выполняется при описании класса в секции interface модуля, а их программный код записывается в секции implementation. Однако в отличии от обычных процедур и функций заголовки методов должны иметь уточнённые имена, то есть содержать наименование класса. Пример:

procedure TPeople.GetName;

begin

Writeln('Введите имя человека');

Readln(People.Name);

end;

Внутри методов обращения к полям и другим методам выполняются как к обычным переменным и подпрограммам без уточнения экземпляра объекта. Такое упрощение достигается путём использования в пределах метода псевдопеременной Self (стандартный идентификатор). Этот дополнительный скрытый параметр необходим в тех случаях, когда вы создаёте несколько объектов одного класса, так что каждый раз, когда вы применяете метод к одному из объектов, он должен оперировать именно со своими данными и не влиять на своих объектов-"братьев". Физически Self представляет собой дополнительный неявный параметр, передаваемый в метод при вызове. Этот параметр и указывает экземпляр объекта, к которому данный метод применяется. Практика показывает, что псевдопеременная Self редко используется в явном виде. Её необходимо применять только тогда, когда при написании метода может возникнуть какая-либо двусмысленность для компилятора.

Соседние файлы в папке 1