Полиморфизм

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

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

Поля

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

type

TChildClass = class

FOne: Integer;

FTwo: String;

FThree: TObject;

end;

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

var

MyObject: TChildClass;

begin

MyObject.FOne:= 16;

MyObject.FTwo:= 'Некоторое строковое значение';

end;

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

Методы

Методами называются инкапсулированные в классе процедуры и функции.

Например:

type

TChildClass = class

FOne: Integer;

FTwo: String;

FThree: TObject;

function FirstFunc(x:real):real;

procedure SecondProc;

end;

Для того чтобы обратиться к методам, как и для полей, необходимо использовать составные имена:

var

MyObject: TChildClass;

у: real;

begin

MyObject.SecondProc;

у:= MyObject.FirstFunc(3.14);

end;

Методы, определенные в классе, могут быть статическими, виртуальными, динами­ческими или абстрактными. Тип метода определяется механизмом перекрытия его в по­томках.

Для статических методов перекрытие осуществляется компилятором. Например, пусть у нас имеется описание родительского класса TBase и его потомка TDescedant, содер­жащих одноименный метод MyJoy:

type

TBase = class

procedure MyJoy;

end;

TDescedant = class(TBase)

procedure MyJoy;

end;

var

FirstObject: TBase;

SecondObject: TDescedant;

begin

FirstObject.MyJoy;

SecondObject.MyJoy;

end;

В соответствии с принципом полиморфизма в операторе FirstObject.MyJoy;

вызывается метод, описанный в классе TBase, а в операторе SecondObject.MyJoy;

вызывается метод, описанный в классе TDescedant.

По умолчанию все методы, описанные в классе, являются статическими. Динамические и виртуальные методы отличаются от статических тем, что замеще­ние родительских методов, методами потомков происходит на этапе выполнения програм­мы. Для объявления виртуального метода в родительском классе необходимо исполь­зовать зарезервированное слово virtual, а для объявления динамического метода - за­резервированное слово dynamic. В классе-потомке в заголовке замещающего метода должно быть указано зарезервированное слово override. Например:

type

TBase = class

procedure MyJoy; virtual;

end;

TDescedant = class(TBase)

procedure MyJoy; override;

end;

var

FirstObject: TBase;

SecondObject: TDescedant;

begin

FirstObject.MyJoy;

SecondObject.MyJoy;

end;

Если бы мы захотели, чтобы метод MyJoy в классе TBase был динамическим, слово virtual в заголовке процедуры следует заменить словом dynamic. Различие между вирту­альными и динамическими методами невелико и связано с особенностями реализации их вызовов. Можно сказать, что виртуальные методы более эффективны с точки зрения затрат времени, а динамические методы позволяют более рационально использовать оперативную память.

Абстрактными называются виртуальные или динамические методы, которые опреде­лены в классе, но не содержат никаких действий, никогда не вызываются и обязательно должны быть переопределены в классах-потомках. Объявляется абстрактный метод при помощи зарезервированного слова abstract, расположенного после слов virtual или dynamic, например:

procedure MyMetod; virtual; abstract;

Основное предназначение абстрактных методов - быть родоначальником иерархии конкретных методов в классах-потомках.

В любом классе содержатся два специальных метода — конструктор и деструктор. Эти методы содержатся в классе-родоначальнике всех остальных классов - TObject и, сле­довательно, наследуются потомками. Как и другие методы, они могут быть изменены в классах-потомках, т. е. перекрыты. В классе TObject и в большинстве его потомков кон­структор и деструктор называются Create и Destroy соответственно.

Конструкторы предназначены для создания и инициализации объекта. Дело в том, что объект в языке Object Pascal является динамической структурой и переменная-объект содержит не сами данные, а ссылку на них. Конструктор распределяет объект в динами­ческой памяти и присваивает полям объекта начальные значения. При этом поля поряд­ковых типов в качестве начального значения получают 0, строкового — пустую строку, поля-указатели - значение nil, поля-варианты — Unassigned. Кроме того, конструктор помещает ссылку на созданный объект в переменную Self, которая автоматически объяв­ляется в классе. Из сказанного следует, что обращение к полям, свойствам и методам объекта должно осуществляться только после вызова конструктора. Деструктор освобождает динамическую память и разрушает объект. Для объявления конструктора и деструктора используются зарезервированные слова constructor и destructor соответственно. Например:

type

TSample = class

Text:string;

constructor Create;

destructor Destroy;

end;

Для того чтобы создать объект, необходимо применить метод-конструктор к классу объекта:

var

MyObject: TSample;

begin

MyObject:= TSample.Create;

end;

Если создается класс-потомок и при его создании планируется осуществить некото­рые дополнительные действия, отсутствующие у класса-родителя, то в конструкторе класса-потомка следует сначала вызвать конструктор своего родителя, а уже потом осу­ществлять дополнительные действия. Вызвать любой перекрытый метод родительского класса можно при помощи зарезервированного слова inherited (унаследованный). Напри­мер, если в классе TDescedant имеется свой собственный конструктор

type

TDescedant = class(TBase)

FMark: Boolean;

constructor Create(Mark:Boolean);

end;

то его реализация могла бы быть такой:

constructor TDescedant.Create(Mark:Boolean);

begin

inherited Create;

FMark:= Mark;

end;

где вызов родительского конструктора осуществляется оператором

inherited Create;

а оператор

FMark := Mark;

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

Кроме деструктора Destroy, в базовом классе TObjec t определен метод Free, кото­рый прежде проверяет, был ли объект на самом деле реализован и только потом вызы­вает метод Destroy. Если объект не был создан конструктором, то обращение к дест­руктору, приведет к генерации исключительной ситуации. Следовательно, для уничтоже­ния ненужного объекта удобнее использовать метод Free, например:

MyObject.Free;


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: