- •Лабораторная работа № 1
- •Теоретические сведения
- •Программа работы
- •Контрольные вопросы
- •Лабораторная работа № 2
- •Теоретические сведения
- •Программа работы
- •Контрольные вопросы
- •Лабораторная работа № 3
- •Теоретические сведения
- •Программа работы
- •Контрольные вопросы
- •Лабораторная работа № 4 понятие класса
- •Теоретические сведения
- •Программа работы
- •Контрольные вопросы
- •Лабораторная работа № 5 статические методы класса
- •Теоретические сведения
- •Программа работы
- •Контрольные вопросы
- •Лабораторная работа № 6 механизм наследования
- •Теоретические сведения
- •Программа работы
- •Контрольные вопросы
- •Лабораторная работа № 7 виртуальные методы класса
- •Теоретические сведения
- •Программа работы
- •Контрольные вопросы
- •Лабораторная работа № 8
- •Теоретические сведения
- •Программа работы
- •Контрольные вопросы
- •Библиографический список
- •Содержание
Лабораторная работа № 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;
Концепция полиморфизма позволяет значительно упростить сложность написания больших программ и расширить возможности современного программиста, активно использующего объектно-ориентированный подход в программировании.