Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции програм_new_последняя версия1.doc
Скачиваний:
14
Добавлен:
14.09.2019
Размер:
697.34 Кб
Скачать

Статические методы.

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

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

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

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

Например:

type TFigure=class

procedure draw;

end;

TRectangle=class (TFigure)

procedure draw; {эта процедура будет перекрыта

предыдущей}

end;

… … … …

var Figure:TFigure;

Rectangle:TRectangle;

begin

Figure:=TFigure.create;{конструктор create уноследова

у предка}

Figure.draw;

{вызывается метод draw класса TFigure}

Figure.free; {уничтожаем объект Figure}

Figure:=TRectangle.create; {Figure-новая, отличная от

предыдущей}

Figure.draw;

{вызывается метод draw класса TRectangle}

Figure.free;

Rectangle:=TRectangle.create; {описываем новую

переменную}

Rectangle.draw;

{вызывается метод draw класса TRectangle}

Rectangle.free;

end.

Здесь разные методы с именами draw вызываются в разных классах. Их адрес определяется при компиляции, поэтому статические методы вызываются быстрее всех.

Полиморфизм. Виртуальные и динамические методы.

Принципиально отличаются от статических виртуальные и динамические методы.

В Delphi чаще используется динамическое замещение методов на этапе прогона программы. Для реализации этого метод, замещаемый в родительском классе должен объявляться как динамический (dynamic) или виртуальный (virtual). Встретив такое объявление компилятор создает две таблицы:

DMT – Dynamic Method Table

VMT – Virtual Method Table

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

Пример1. Пусть существует некоторый обобщенный класс для хранения данных и два его потомка для хранения строк и целых чисел:

Пример 1:

Type TField=class {класс родитель}

function GetData: string; virtual; abstract;

end;

TStringField=class(TField) {класс потомок}

FData:string;{поле}

Function GetData: string;  override;{метод

перекрыт}

end;

TIntegerField=class(TField){класс потомок}

FData:integer;{поле}

function GetData: string; override;{перекрыт}

end;

. . . . .

function TStringField.GetData;{описывается метод

GetData класса TStringField}

begin

Result:=FData;

end;

function TIntegerField.GetData; {описывается

метод GetData класса TIntegerField}

begin

Result:=IntToStr(FData);

end;

. . . . .

Procedure Show (F:TField);

begin

Form1.Label1.Caption:= F.GetData;

end;

. . . . .

В этой задаче классы TIntegerField и TStringField содержат разнотипные поля данных FData и единственное что они умеют – это сообщать о значении своих данных текстовой строкой при помощи метода GetData

В каждом классе сообщается о значении разнотипных полей. Внешняя процедура Show получает объект в виде параметра и показывает строку данных. (Form1.Label1.Caption:= F.GetData;) В процедуре Show параметр F описан как объект класса TField. Это значит, что в нее можно передавать объекты классов TStringField, TIntegerField как потомков класса TField.

Возникает вопрос: чей метод GetData при этом будет вызван? Ответ: тот, который соответствует классу фактически переданного объекта.

Т.о. правило соответствия типов языка Object Pascal гласит: объекту, как указателю на экземпляр объектного типа может быть присвоен адрес любого экземпляра любого из дочерних типов. Этот принцип называется полиморфизмом. Полиморфизм – наиболее важный принцип ООП.

В нашем примере программисту, пишущему процедуру Show важно лишь, что любой объект, переданный в нее, является потомком класса TField.

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