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

Лабораторная работа № 8

ПЕРЕОПРЕДЕЛЕНИЕ ОПЕРАТОРОВ В ЯЗЫКЕ С++

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

Теоретические сведения

Полиморфизм (Polymorphism) – это механизм, который позволяет использовать одно и тоже имя для решения схожих, но технически различных задач.

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

procedure<Имя метода>(<Список параметров>);virtual;

procedure<Имя метода>(<Список параметров>);dynamic;

function<Имя метода>(<Список параметров>): <Тип

возвращаемого значения>; virtual;

function<Имя метода>(<Список параметров>): <Тип

возвращаемого значения>; dynamic;

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

Если метод объявлен динамическим, то его адрес помещается в специальную таблицу динамических методов (DMT–DynamicMethodTable), которая также находится внутри каждого класса. В отличие от виртуальных методов, в таблицеDMTхранятся адреса только тех динамических методов, которые объявлены в данном классе, а не во всех его родителях. Это позволяет существенно сократить объем занимаемой памяти, однако вызов динамических методов происходит медленнее чем виртуальных так как, для поиска их адреса, возможно, будет необходимо просмотреть ни одну таблицуDMT. Дело в том, что методу, объявленному с помощью директивыdynamic, компилятор автоматические присваивает уникальный номер, который помещается в таблицеDMTперед адресом самого метода. Во время выполнения программы последовательно осуществляется просмотр таблицыDMTданного класса, и если соответствующий номер не будет найден, то поиск продолжится в таблицахDMTего родителей, вверх по всей иерархической цепочке.

Пример:

TFruit = class(TObject)

procedure Juice; virtual;

end;

TApple = class(TFruit)

procedure Jam; virtual;

end;

TAnis = class(TApple);

Таблицы VMTобъявленных классов.

Класс TFruit

Класс TApple

Класс TAnis

Адрес виртуального метода Juice

Адрес виртуального метода Juice

Адрес виртуального метода Juice

Адрес виртуального метода Jam

Адрес виртуального метода Jam

TFruit = class(TObject)

procedure Juice; dynamic;

end;

TApple = class(TFruit)

procedure Jam; dynamic;

end;

TAnis = class(TApple);

Таблицы DMTобъявленных классов.

Класс TFruit

Класс TApple

Класс TAnis

Число динамических методов (1)

Число динамических методов (1)

Число динамических методов (0)

Номер динамического метода (-1)

Номер динамического метода (-2)

Адрес динамического метода Juice

Адрес динамического метода Jam

Так как виртуальные и динамические медтоды вызываются медленнее чем статитические, то их необходимо использовать только тогда, когда предполагается их дальнейшее переопределение в классах наследниках. Для этого в языке ObjectPascalпредусмотрена директиваoverride:

procedure<Имя метода>(<Список параметров>);override;

function<Имя метода>(<Список параметров>): <Тип

возвращаемого значения>; override;

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

TFruit = class(TObject)

procedure Juice; virtual;

end;

TApple = class(TFruit)

procedure Juice; override;

end;

TAnis = class(TApple);

Таблицы VMTобъявленных классов.

Класс Tfruit

Класс Tapple

Класс TAnis

Адрес метода Juice

класса Tfruit

Адрес метода Juice

класса TApple

Адрес метода Juice

класса TApple

TFruit = class(TObject)

procedure Juice; dynamic;

end;

TApple = class(TFruit)

procedure Jam; dynamic;

end;

TAnis = class(TApple);

Таблицы DMTобъявленных классов.

Класс TFruit

Класс TApple

Класс TAnis

Число динамических методов (1)

Число динамических методов (1)

Число динамических методов (0)

Номер динамического метода (-1)

Номер динамического метода (-1)

Адрес метода Juice

класса TFruit

Адрес метода Juice

класса Tapple

Механизм переопределения является вершиной концепции полиморфизма, так как позволяет использовать одно и тоже имя для решения схожих, но технически различных задач. Дело в том, что какой из двух методов Juiceбудет вызван зависит не от заданного типа объекта, а от текущего. Например, если объявить объектFruitи создать его с типомTFruit, то при обращенииFruit.Juiceбудет вызван метод классаTFruit, а если его создать с типомTApple, то при томже самом обращенииFruit.Juiceбудет вызван уже метод классаTApple.

var

Fruit: TFruit; // заданный тип TFruit;

begin

Fruit := TFruit.Create; // текущий тип TFruit

Fruit.Juice; // вызов метода класса TFruit

...................................................

Fruit := TApple.Create; // текущий тип TApple

Fruit.Juice; // вызов метода класса TApple

Fruit.Free;

end;

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

Например,

TFruit = class(TObject)

procedure Juice; virtual; abstract;

procedure Jam; dynamic; abstract;

end;

TApple = class(TFruit)

procedure Juice; override;

procedure Jam; override;

end;

TOrange = class(Tfruit)

procedure Juice; override;

end;

TLemon = class(TFruit)

procedure Juice; override;

end;

Так как методы родительского класса не должны выполнять никаких действий (они служат лишь для дальнейшего переопределения), то их тело следует оставлять всегда пустым. Например,

procedureTFruit.Juice;

begin

end;

procedureTFruit.Jam;

begin

end;

Чтобы этого не делать, достаточно объявить их абстрактными, указав специальную директиву abstractпосле директивvirtualилиdynamic.

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

var

Fruit: TFruit;

begin

case RadioGroup1.ItemIndex of

0: Fruit := TApple.Create;

1: Fruit := TOrange.Create;

2: Fruit := TLemon.Create;

end;

Fruit.Juice;

Fruit.Free;

end;

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