Delphi. Урок 18. Классы и объекты

Уроки для начинающих   3 марта 2013  Автор статьи: admin 

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

Описание класса

Прежде чем создавать какие-то объекты, давайте создадим хотя бы один тип объектов, т.е. класс. Класс описывается в разделе type следующим образом:
[cc lang=»delphi»]type
TBook = class
public
PagesCount: integer;
Title, Author: string;

function CompareWithBook(OtherBook: TBook): integer;
procedure ShowTitle;

constructor Create(NewTitle, NewAuthor: string; NewPagesCount: integer);
end;[/cc]
Давайте постепенно разбираться, что же это такое. Мы создали класс с именем TBook. Если записи описываются при помощи ключевого слова record, то классы описываются при помощи ключевого слова class. После слова class и до end идет перечисление описаний всевозможных полей и методов (свойств и процедур/функций), которые существуют у данного класса. Ключевое слово public является модификатором доступа, их мы будем рассматривать несколько позже. Пока нам достаточно знать, что поля и методы, указанные после public доступны из всех участков кода (за исключением особенных случаев). При указывании полей и методов важно помнить, что сначала указываются поля, и только потом методы. Поля указываются как и обыкновенные переменные внутри записи, это видно на примере. Методы описываются также как и обычные процедуры и функции. Ключевой особенностью методов внутри класса является то, что внутри метода мы имеем доступ ко всем другим полям и методам данного класса (если не ограничивать доступ модификаторами). Полезной возможностью является то, что в качестве типов полей и параметров методов можно использовать и сам описываемый класс. Т.е. мы на примере описали метод CompareWithBook с параметром TBook, который указывает на другой экземпляр класса TBook. Таким образом мы сможем реализовать сравнение двух книг по количеству страниц. «Что же такое constructor ?» -, спросите вы. Это метод, который реализует процесс создания экземпляра класса. Да, в отличие от записей, экземпляры классов нужно создавать. Обычно процесс создания экземпляра класса (объекта) заключается в заполнении полей объекта какими-либо изначальными данными и создании вложенных объектов, которые объявлены внутри создаваемого объекта. Да, в качестве полей класса могут выступать не только обыкновенные переменные, но и объекты (экземпляры какого-то класса, возможно этого же). Конструктор в классе реализовывать необязательно. Но объекты все равно придется создавать при помощи уже существующего по-умолчанию конструктора с именем Create. В нашем случае мы создадим свой конструктор.

Реализация методов класса

Вы уже наверное догадались, что наши методы, как и обычные процедуры и функции, Установим курсор на названии любого метода и нажмем сочетание клавиш Ctrl+Shift+C. Это создаст нам пустые шаблоны реализаций всех методов класса. Выглядеть это будет примерно следующим образом:
[cc lang=»delphi»]{ TBook }

function TBook.CompareWithBook(OtherBook: TBook): integer;
begin

end;

constructor TBook.Create(NewTitle, NewAuthor: string; NewPagesCount: integer);
begin

end;

procedure TBook.ShowTitle;
begin

end;
[/cc]
Начнем с реализации самого интересного — конструктора. Как уже упоминалось выше, внутри конструктора мы должны присвоить некоторым полям определенные значения (не обязательно всем) и создать все нужные нам вложенные объекты. Т.к. вложенных объектов внутри нашего класса нет, да и рассматривать создание объекта (экземпляра класса) мы будем чуть позже, то нам нужно только присвоить полям Title, Author и PagesCount нужные значения. Эти значения мы будем передавать при помощи параметров конструктора. Однако в конструкторе (в отличие от нашего примера) мы можем и не присваивать значения всем полям. Нетрудно догадаться, каким образом будет выглядеть реализация конструктора:
[cc lang=»delphi»]constructor TBook.Create(NewTitle, NewAuthor: string; NewPagesCount: integer);
begin
Title := NewTitle;
Author := NewAuthor;
PagesCount := NewPagesCount;
end;[/cc]
Я уже говорил, что внутри методов класса мы имеем доступ ко всем другим полям и методам данного класса (за исключением описанных внутри специальных модификаторов доступа, их мы будем рассматривать позже). Так вот и в конструкторах (как и в методах) мы можем работать с полями класса как с локальными переменными. Этим мы и воспользовались — присвоили полям класса изначальные значения.
Теперь реализуем метод CompareWithBook:
[cc lang=»delphi»]function TBook.CompareWithBook(OtherBook: TBook): integer;
begin
Result := Abs(OtherBook.PagesCount — PagesCount);
end;[/cc]
В этом примере мы получаем модуль разности количества страниц другой книги и данной. В нашем случае OtherBook — это объект типа/класса TBook. Т.е. OtherBook — является экземпляром класса TBook. Методу одной книги CompareWithBook, который мы будем использовать, мы будем передавать в качестве параметра другую книгу типа TBook. И соответственно к своему полю PagesCount из метода данного класса можно обратиться как и к локальной переменной. Также, мы можем обращаться к своим полям и методам при помощи зарезервированной переменной Self:
[cc lang=»delphi»]Result := Abs(OtherBook.PagesCount — Self.PagesCount);[/cc]
Ну и наконец реализуем метод ShowTitle. Этот метод будет выводить в сообщении ShowMessage автора книги и название в кавычках. Еще один наглядный пример обращения к полям класса:
[cc lang=»delphi»]procedure TBook.ShowTitle;
begin
ShowMessage(Author + ‘ «‘ + Title + ‘»‘);
end;[/cc]

Создание и использование объектов

После того как мы описали класс и реализовали все его методы, мы можем использовать наш класс, а именно создавать экземпляры этого класса — объекты. Сначала опишем объект в разделе var как обыкновенную переменную:
[cc lang=»delphi»]var
MyBook: TBook;[/cc]
Затем приступим к созданию объекта. Для того чтобы использовать экземпляр класса, просто объявить его недостаточно. Его нужно создать. Если объект не создать, то при первом обращении к какому-либо полю или методу класса, неминуемо будет вызвана ошибка «Access Violation». Поэтому научимся создавать объекты:
[cc lang=»delphi»]MyBook := TBook.Create(‘Delphi для начинающих’, ‘Cyberexpert’, 1000);[/cc]
Воспользуемся нашим конструктором Create. Как вы видите, мы должны присвоить нашему объекту конструктор создаваемого класса. При необходимости конструктору нужно передать параметры. Конструкторов у класса может быть несколько. Вот теперь мы можем использовать наш объект так как нам нужно. Давайте создадим еще одну книгу:
[cc lang=»delphi»]MyBook2 := TBook.Create(‘Delphi для начинающих 2’, ‘Cyberexpert’, 1300);[/cc]
И попробуем сравнить эти книги при помощи нашего метода CompareWithBook у класса TBook. Для этого вызовем этот метод у одного объекта, и в качестве параметра передадим другой объект типа TBook:
[cc lang=»delphi»]a := MyBook.CompareWithBook(MyBook2);
ShowMessage(IntToStr(a));[/cc]
Можем также вывести на экран автора и название книги:
[cc lang=»delphi»]MyBook.ShowTitle;[/cc]
Предположим мы каким-то образом использовали наш объект и теперь он стал нам не нужен. Зачем ему занимать лишнюю оперативную память? Давайте его удалим! Сделать это можно при помощи деструктора. У каждого класса по-умолчанию помимо конструктора Create существует деструктор Destroy. Т.е. их не надо описывать и создавать, у каждого класса они уже есть. Только в нашем нестандартном конструкторе мы реализовали присвоение полям начальных данных. Если бы мы не создали свой конструктор, то использовали бы стандартный при создании объекта, и изначальных параметров передать не смогли бы. Также можно создать и деструктор, давайте его сделаем и будем в нем выводить некоторое сообщение:
[cc lang=»delphi»] TBook = class
public
PagesCount: integer;
Title, Author: string;

function CompareWithBook(OtherBook: TBook): integer;
procedure ShowTitle;

constructor Create(NewTitle, NewAuthor: string; NewPagesCount: integer);
destructor Destroy; // так деструктор будет выглядеть в описании класса
end;[/cc]
Реализация деструктора:
[cc lang=»delphi»]destructor TBook.Destroy;
begin
ShowMessage(‘Уничтожается книга «‘ + Title + ‘»‘);
end;[/cc]
Т.е. мы будем выводить сообщение перед уничтожением объекта. Для чего же еще нужен деструктор? Для того чтобы уничтожать также и все вложенные в классе объекты. Т.е. когда внутри класса существует объект, чтобы его использовать, мы должны этот «подобъект» создать в конструкторе и уничтожить в деструкторе.
Соответственно, чтобы вызвать деструктор мы вызовем его как обыкновенный метод тогда, когда нам нужно удалить объект:
[cc lang=»delphi»]MyBook.Destroy;[/cc]
В этом уроке мы рассмотрели самые базовые основы ООП. В следующих уроках мы продолжим знакомиться с классами и их возможностями. Исходный код проекта, созданного в этом уроке, можно скачать здесь.

Научиться программировать

  • на Delphi

  • на Java

  • на C++