Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
4 ООП Объекты и классы_Delphi.doc
Скачиваний:
54
Добавлен:
13.02.2015
Размер:
317.44 Кб
Скачать
    1. Принципы ооп

Инкапсуляция (encapsulation). Работа с данными и детали ее реализации скрыты от внешнего пользователя объекта. Преимущества инкапсуляции за­ключаются в модульности и изоляции кода объекта от другого кода программы.

Наследование (inheritance). Возможность создания новых объектов, которые наследуют свойства и поведение родительских объектов. Такая концепция позволяет создавать иерархии объектов (например, библиотека VCL), вклю­чающие наборы объектов, порожденных от одного общего предка и обла­дающих все большей специализацией и функциональностью по сравнению со своими предшественниками, но, тем не менее, использующие все возможно­сти родительских классов.

Преимущества наследования заключается, в первую очередь, в совме­стном использовании многими объектами общего кода. От каких классов унаследован объект Form1, о котором говорилось выше, можно посмотреть, если щелкнуть на пунктах меню View=>Browser (или нажать клавиши <Shift+Ctrl+B>) и щелкнуть на кнопке Classes. Вы увидите иерархию насле­дования для созданного типа TForm1 (рис. 3.1).

Рис. 3.1. Иерархия наследования для типа TForm1

Видно, что вверху иерархии находится класс TObject, о котором поговорим позже.

Полиморфизм (polymorphism). Слово "полиморфизм" означает "много форм". В данном случае под этим подразумевается, что вызов метода объекта для пе­ременной приведет к выполнению кода, конкретного экземпляра класса, со­ответствующего данной переменной.

Обо всем этом подробнее поговорим ниже, и начнем с элементов класса.

    1. Элементы классов

      1. Поля

Поле (Field) можно также определить как переменную экземпляра (Instance variable), представляющую собой данные для объекта. Поле в объекте подоб­но полю в записи языка Pascal, но в отличие от записи, к полям в объекте обычно не разрешен прямой доступ. Это способствует защите полей от случай­ного или предумышленного искажения.

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

FQuantity: Integer;

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

Итак, поля предназначены для использования внутри класса. Однако класс должен каким-либо образом взаимодействовать с другими классами или программными элементами приложения.

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

      1. Области видимости

Object Pascal предоставляет дополнительный контроль степени доступа к членам классов (полям и методам) с помощью директив protected, private, public, published и automated, открывающих соответствующие разделы объяв­лений, или, как принято говорить, – интерфейсы класса. За каждой из ди­ректив может следовать любое необходимое количество объявлений полей или методов.

Каждый интерфейс обеспечивает следующий уровень доступа.

  • Private (закрытый). Объявленные в данном разделе переменные и ме­тоды доступны только для того кода, который находится в блоке реа­лизации самого объекта. Директива private скрывает особенности реа­лизации объекта от пользователей и защищает члены этого объекта от непосредственного доступа и изменения извне.

  • Protected (защищенный). Члены класса, объявленные в разделе protected, доступны объектам, производным от данного класса. Это по­зволяет скрыть внутреннее устройство объекта от пользователя и в то же время обеспечить необходимую гибкость, а также эффективность доступа к полям и методам объекта для его потомков.

  • Public (открытый). Объявленные в этом разделе члены объекта доступ­ны в любом месте программы. Конструкторы и деструкторы всегда должны быть объявлены как public.

  • Published (экспортируемый). Для членов объекта, объявленных в дан­ном разделе, в процессе компиляции будет создана информация о ти­пах времени выполнения (RTTI – Runtime Type Information). Это по­зволит другим элементам приложения получать информацию об эле­ментах объекта, объявленных как published. В частности, подобная информация используется инспектором объектов при построении спи­сков свойств объектов.

  • Automated (автоматизированный). Этот раздел сохранен только для обес­печения совместимости с Delphi 2.

      1. Методы

Методы (Methods) представляют собой процедуры и функции, принадлежа­щие классу. Можно сказать, что методы определяют поведение класса.

Итак, методом называется объявленная в классе функция или процедура, которая используется для работы с полями и свойствами класса. Согласно принципам ООП, обращаться к свойствам класса можно только через его методы.

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

В классе всегда должны присутствовать два важнейших метода: конструктор и деструктор.

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

Создание метода – процесс, состоящий из двух этапов. Сначала следует объявить метод в объявлении класса, а затем создать код его реализации.

На­пример, выполним следующее.

1. Создадим новый проект типа Application.

2. Откроем инспектор объектов (клавиша <F11>) и щелкнем на вкладке Events (События).

3. Два раза щелкнем на поле OnClick.

В редакторе кодов получим следующую программу (см. листинг ниже), где в классе TForm1 появится процедура FormClick, а в разделе реализации – описание этой процедуры.

unit Unit1;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

Dialogs;

type

TForm1 = class(TForm)

procedure FormClick(Sender: TObject);

private

{ Private declarations }

public

{ Public declarations }

end;

var

Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormClick(Sender: TObject);

begin

... { Здесь что-то выполняется }

end;

end.

Таким образом мы создали пустую процедуру обработки щелчка мыши. Можно ее заполнить соответствующими кодами и получить нужный эффект.

Например, можно изменить цвет фона окна на черный, для чего поместим в описание процедуры TForm1.FormClick (между begin.. .end) следующую строку:

Form1.Color := clBlack;

и запустим программу (клавиша <F9>). После того как появится окно, щелк­нем на нем мышью и наблюдаем эффект.

Типы методов

Методы объекта могут быть описаны как статические (static), виртуальные (virtual), динамические (dinamic) или как методы обработки сообщения (message-handling), для чего к ним добавляются соответствующие директивы.

  • Статические методы. Статические методы работают подобно обычным процедурам или функци­ям. Этот тип методов устанавливается по умолчанию. Адрес такого метода известен уже на стадии компиляции, и компилятор в коде программы оформляет все вызовы данного метода как статические. Такие методы рабо­тают быстрее других, однако не могут быть перегружены в целях полимор­физма объектов.

  • Виртуальные методы. Вызов виртуальных методов из-за возможности их перегрузки немного сложнее, чем вызов статических, так как во время компиляции адрес конкрет­ного вызываемого метода не известен. Для решения этой задачи компилятор строит таблицу виртуальных методов (VMT – Virtual Method Table), обеспечи­вающую определение адреса метода в процессе выполнения программы. VMT содержит все виртуальные методы предка и виртуальные методы самого объек­та, поэтому виртуальные методы используют несколько больший объем памяти, чем методы динамические, однако их вызов происходит быстрее.

  • Динамические методы. Динамические методы в целом подобны виртуальным методам, но об­служиваются другой диспетчерской системой. Каждому динамическому ме­тоду компилятор назначает уникальное число и использует его вместе с адре­сом метода для построения таблицы динамических методов (DMT– Dynamic Method Table). В отличие от VMT, DMT содержит методы лишь данного объ­екта, благодаря чему обеспечивается экономия используемой памяти, но за­медляется вызов метода, поскольку для поиска его адреса, скорее всего, будет пересмотрена не одна DMT в иерархии объектов.

  • Методы обработки сообщения. Методы обработки сообщений предназначены для обработки приходящих сообщений, с помощью которых происходит обмен информацией в операци­онной системе Windows. Значе­ние после ключевого слова message определяет сообщение, в ответ на которое вызывается данный метод. Такие методы создаются для реакции на те или иные сообщения Windows. Они никогда не вызываются непосредственно из программы.

Например:

type

TTextBox = class(TCustomControl)

private

procedure WMCharfvar Message: TWMChar); message WM_CHAR;

end;

где WM_CHAR – константа, определяющая данное сообщение. Две буквы WM (Windows Message) говорят о том, что это сообщение операционной системы Windows. В данном случае это связано с нажатием клавиш клавиатуры.

Методы класса

Для использования каждого метода необходимо сначала создать объект (экземпляр класса) и только потом делать вызов метода в программе, для чего используются имя объекта и имя метода, написанные через точку.

Например, в ранее приведенном классе TForm1 вызов метода FormClick просходит как TForml.FormClick. Но если перед объявлением метода поставить ключевое сло­во class, то этот метод может быть вызван как обычная процедура или функ­ция без создания экземпляра класса, членом которого является данный ме­тод. (Аналоги таких методов в языке C++ объявляются как static.)

Необхо­димо иметь в виду, что при создании подобных методов нельзя использовать никакой информации экземпляра класса, поскольку это приведет к ошибке компиляции.

Переопределение методов

Переопределение (overriding) методов в Object Pascal реализует концепцию полиморфизма, позволяя изменять поведение метода от наследника к на­следнику.

Переопределение метода возможно только в том случае, если первоначально он был объявлен как virtual или dynamic.

Для переопределе­ния метода при его объявлении вместо ключевых слов virtual или dynamic следует указать ключевое слово override.

Ниже приведен пример переопре­деления методов, где метод Draw переопределен в двух унаследованных классах TRectangle и TEllipse.

Type

TFigure = class

procedure Draw; virtual;

end;

TRectangle = class(TFigure)

procedure Draw; override;

end;

TEllipse = class(TFigure)

procedure Draw; override;

end;

Здесь первым, объявлен класс TFigure, который затем наследуют классы TRectangle и TEllipse, что видно из объявлений классов, где за ключевым словом class в круглых скобках помещается имя родительского класса.

Директива override приводит к замещению строки описания исходного метода в VMT строкой описания нового метода. Если объявить новые функции с ключевым словом virtual или dynamic, а не override, то вместо замещения старых будут созданы новые методы.

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

Если использовать следующий исполнимый код:

var

Figure: TFigure;

begin

Figure := TRectangle.Create;

Figure.Draw; // вызывает TRectangle.Draw

Figure.Destroy;

Figure := TEllipse.Create;

Figure.Draw; // вызывает TEllipse.Draw

Figure.Destroy;

end;

то, в зависимости от того, какая фигура создается, прямоугольник (TRectangle) или эллипс (TEllipse), вызываются разные методы для их прори­совки, хотя способ вызова один и тот же: Figure.Draw;.

Перегрузка методов

Подобно обычным процедурам и функциям, методы могут быть перегру­жены таким образом, чтобы класс содержал несколько методов с одним име­нем, но с различными списками параметров.

Перегруженные методы должны быть объявлены с указанием директивы overload. Вот пример объявления класса с перегруженными методами.

Type

TSomeClass = class

procedure AMethod(I: Integer); overload;

procedure AMethod(S: string); overload;

procedure AMethod(D: Double); overload;

end;

Дублирование имен методов

Иногда может понадобиться к одному из классов добавить метод, заме­щающий метод с тем же именем, но принадлежащий предку этого класса. В данном случае требуется не переопределить исходный метод, а полностью его заменить. Если просто добавить такой метод в новый класс, то компилятор выдаст предупреждение о том, что новый метод скрывает метод базового класса с тем же именем. Для устранения этой ошибки в новом методе укажи­те директиву reintroduce.

type

T1 = class(TObject)

procedure Test(I: Integer); overload; virtual;

end;

T2 = class(Tl)

procedure Test(S: string); reintroduce; overload;

end;

В следующем коде будут вызываться различные методы.

SomeObject := Т2.Create;

SomeObject.Test('Hello!'); // вызывается T2.Test

SomeObject.Test(7); // вызывается Tl.Test

Указатель Self

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

function TCollection.Add: TCollectionItem;

begin

Result := FItemClass.Create(Self);

end;

где функция Add создает объект типа TCollectionItem для класса, на который происходит ссылка в поле FItemClass и который всегда является наследником TCollectionltem. Например, в кодах:

var MyCollection: TCollection;

MyCollection.Add

Переменная MyCollection передается в метод TCollectionltem.Create.