Создание и разрушение объекта
Введение в объектно-ориентированное программирование
Язык программирования Object Pascal и его достойный преемник, среда программирования Delphi, построены на основе получившей широкое развитие на стыке 70–80-х годов XX века теории объектно-ориентированного программирования (Object-Oriented Programming, OOP). В то время идея описания программ в базисе логических сущностей и взаимодействия между ними не была такой уж бесспорной, а у некоторых оппонентов даже вызывала определенное недоумение.
Пока консервативно настроенные личности занимались критикой новой идеи и всячески пропагандировали традиционный по тем временам процедурный стиль, компания Borland и корпорация Microsoft активно занялись разработкой концептуально новых систем программирования. Спустя сравнительно небольшой промежуток времени на рынке появились среды разработки ПО, совершившие революционный переворот в самой идее программирования. В первую очередь это объектно-ориентированные C++ и Object Pascal, а чуть позднее Microsoft Visual C++, Borland C++ Builder и, конечно же, Borland Delphi.
Появление даже первых версий этих систем поумерило пыл критиков ООП. Трудно придираться к программным продуктам, в которых создание классического примера «Hello, World» занимает не более минуты и обходится без единой строки кода. Для сравнения аналогичная задача на старом добром языке С потребует не менее 50 строк кода.
Подчеркну, что материал этой главы не претендует на «всеобъемлющее изложение концепции объектно-ориентированного программирования». Задача скорее обратная – познакомить читателя с основными понятиями ООП и провести вступительную экскурсию по объектам и классам, дабы подготовить новичков к изучению среды программирования Delphi. Более углубленная версия предлагается в главе 16 «Создание компонентов».
Объект и класс
Уже само название концепции «объектно-ориентированное программирование» указывает на то, что ключевой фигурой в OOП является объект. Что же это такое? В окружающей нас среде объект – это то, что можно пощупатьруками, это книга, кнопка на клавиатуре, сама клавиатура, настольная лампа, проезжающий за окном автомобиль. Каждый объект обладает некоторыми характеристиками, сравнивая которые мы можем судить о сходстве или различии объектов. Так, несмотря на схожесть кнопок клавиатуры, мы различаем их по сопоставленному им символу алфавита. Кроме того, есть характеристики, взглянув на которые мы можем судить о текущем состоянии объекта, например, лампа включена или выключена, автомобиль мчится со скоростью 60 км/ч.
Все присущие объекту характеристики в терминах OOП называют полями. По сути, это принадлежащие объекту переменные определенного типа, в которые записываются значения, отражающие состояние объекта. Для управления объектом предназначены его методы. Настольной лампой управляют два ключевых метода: включить и выключить. У автомобиля этих методов значительно больше: он заводится, набирает скорость, изменяет направление движения, замедляет движение и все это время пожирает бензин. В первую очередь методы воздействуют на поля объекта. Так, практически все методы автомобиля сосредоточены вокруг поля, описывающего его скорость. Если методы объекта возвращают какое-нибудь значение, то они реализуются в виде функции, в противном случае метод представляется процедурой.
Объект не может возникнуть из воздуха, среда программирования каким-то образом должна быть проинформирована о его характеристиках. Поэтому предварительно программист описывает объект; такое описание называется классом. Класс – это чертеж будущего объекта, в котором учитываются не только его конструктивные элементы (поля), но и определяются способы управления этими элементами – методы класса.
Определение класса начинается с ключевого слова type, за которым следуют имя класса, его поля и методы. Завершается описание директивой end. Например, объявление класса простейшего автомобиля могло бы выглядеть примерно так:
Type
TAutomobile = class
fSpeed : smallint;
procedureSetSpeed(Value : SmallInt);
end;
Созданный на основе класса объект способен только изменять скорость – содержимое поля fSpeed.
В объявление класса могут входить другие классы; таким образом можно создавать сложные составные объекты. Допустим, что мы хотим снабдить автомобиль двигателем. Для этого объявим новый класс, описывающий этот двигатель:
Type
TEngine = class//класс двигатель
fOn : Boolean; //поле вкл/выкл
procedureEngineOn; //включить двигатель
procedureEngineOff; //выключить двигатель
end;
Двигатель TEngine умеет запускаться и останавливаться, для чего реализованы соответствующие методы. О текущем состоянии двигателя можно судить по полю fOn.
Type
TAutomobile = class
fSpeed : smallint;
fEngine : TEngine; //интеграция класса TEngine в состав класса TAutomobile
procedureSetSpeed(Value : SmallInt);
end;
Двигатель интегрируется в состав общего класса автомобиля в виде отдельного поля. Для обращения к полю или методам вложенного класса необходимо лишь указать его принадлежность. Например, для того чтобы завести автомобиль, потребуется следующая строка кода:
varAutomobile : TAutomobile;
…
Automobile.fEngine.EngineOn;
Скажете, это все теория. Хорошо, взглянем на классы и объекты с практической стороны. При разработке обычного приложения с объявлением классов и созданием объектов Delphi справляется без посторонней помощи. Чтобы убедиться в этом, запустите среду программирования. По умолчанию создается новый проект с одной-единственной формой. Заглянув в редактор кода, вы увидите следующие строки:
unitUnit1;
Interface
Uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs;
Type
TForm1 = class(TForm)
Private
{ Private declarations }
Public
{ Public declarations }
end;
varForm1: TForm1;
Implementation
{$R *.dfm}
end.
Пока наш проект практически пуст. В нем объявлен единственный класс формы TForm1, а в разделе переменных объявлена переменная объектного типа Form1: TForm1. После старта приложения и создания экземпляра класса TForm1 в этой переменной будет храниться ссылка на объект. А теперь разместите на поверхности формы любой из компонентов, например строку ввода (элемент управления TEdit со страницы Standard, рис. 5.1). После этого вернитесь в редактор кода. В теле объявления класса TForm1 появилось одно очень важное изменение – новый объект Edit1, создаваемый из класса TEdit.
Type
TForm1 = class(TForm)
Edit1: TEdit;
Private
{ Private declarations }
Public
{ Public declarations }
end;
Отметим одну важную особенность, касающуюся обращения к объекту. Если нам потребуется обратиться к строке ввода Edit1 из этого же модуля Unit1, то достаточно просто указать имя вызываемого компонента:
Edit1.Text:= 'Hello World!';
Однако приложения очень часто состоят из двух и более форм. И если вы попытаетесь из другой формы изменить текст в строке ввода формы Form1 предложенным выше способом, то компилятор сообщит, что он не знает о существовании компонента с именем Edit1.
При обращении к компоненту, принадлежащему другой форме, сначала надо сослаться на форму, владеющую этим компонентом:
Form1.Edit1.Text:= 'Hello World!';
Это правило также относится к вызову всех опубликованных (описанных в секции
public) полей и методов другой формы.
Создание и разрушение объекта
Все размещаемые на поверхности формы компоненты создаются и уничтожаются автоматически. В простейших приложениях программисту, как правило, даже нет необходимости вмешиваться в их жизненный цикл. Но если вы собираетесь создавать профессиональные программные продукты, то безусловно стоит узнать, как рождается и умирает объект.
Любой класс снабжен двумя специализированными методами: конструктором (constructor) и деструктором (destructor). Конструктор предназначен для создания экземпляра класса; в результате его вызова рождается новый объект и инициализируются его поля. Обычно конструктор реализуется в виде функции Create(). Деструктор – это антипод конструктора; его задача кардинально противоположная – уничтожить объект и освободить отведенные под него системные ресурсы. По существующей традиции деструктор реализуется в виде процедуры Destroy().
Описание класса, включающее конструктор и деструктор, выглядит примерно так:
Type
TAutomobile = class
…
constructorCreate;
destructorDestroy;
end;
Пусть вас не вводит в недоумение несколько нетрадиционный синтаксис объявления этих методов. В данном случае нет необходимости применять привычные ключевые слова procedureи function, а также не надо указывать тип возвращаемого функцией Create() значения, т. к. компилятор и без нашей помощи знает, что конструктор создает экземпляр класса TAutomobile. На практике применение конструктора и деструктора не вызывает особых затруднений:
varAutomobile : TAutomobile;
Begin
Automobile:= TAutomobile.Create;
//операции с объектом Automobile
Automobile.Destroy;
end;
Программист объявляет переменную объектного типа, конструирует этот объект, проводит с ним запланированные операции и затем уничтожает его. Зачастую обязанности по созданию и уничтожению объектов берет на себя Delphi. Например, при разработке приложения средней сложности среда программирования в состоянии взять на себя полную ответственность за создание формы и принадлежащих ей компонентов. Но если программист намерен создавать объекты самостоятельно, то он должен помнить правило: все созданное нашими руками по окончании работы должно быть уничтожено нами же. В этом случае не принято полагаться на сообразительность любой среды разработки, в том числе и Delphi.
Функция Create() относится к группе так называемых методов класса (class functions).
Это особая категория методов, которые могут вызываться не от имени
объекта, а от имени его класса.
Операторы класса
В Delphi предусмотрено два специализированных оператора, называемых операторами класса: isи as. Оператор isпредназначен для проверки принадлежности объекта к определенному классу:
if(MyObject isTComponent)=True then…
Ключевая особенность оператора isв том, что он проверяет не только непосредственного предка объекта, а всю иерархическую цепочку наследования объекта в целом. И если TComponent будет предком объекта MyObject даже в десятом колене, то конструкция вернет true.
Оператор asназывается оператором приведения типа. Это очень грозное и притом опасное оружие, поэтому использование оператора asдолжно быть максимально продуманным.
with(MyObject asTControl) do…
Оператор приведения типа позволяет явным образом указывать Delphi, что объект MyObject должен действовать как экземпляр класса TControl. И горе той программе, которая с помощью оператора asпопробует заставить объект выполнить несвойственные ему действия. Такая попытка в лучшем случае закончится вызовом исключительной ситуации. Поэтому сразу приведу пример безопасного приведения типов:
vari : integer;
Begin
fori:=0 toForm1.ComponentCount-1 do
Дата добавления: 2016-03-15; просмотров: 1045;