Опубликован: 03.09.2010 | Уровень: для всех | Доступ: свободно
Лекция 7:

Иерархии объектов. Работа с объектами в динамической памяти

< Лекция 6 || Лекция 7: 12345
Аннотация: Описание потомков объекта. Наследование полей и методов. Раннее и позднее связывание. Механизм виртуальных методов. Конструкторы и деструкторы. Размещение объектов в динамической памяти. Полиморфные объекты. Контейнер (список) полиморфных объектов.

Наследование

Презентацию к данной работе Вы можете скачать здесь.

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

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

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

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

Допустим, нам требуется ввести в игру еще один тип персонажей, который должен обладать свойствами объекта monster, но по-другому выглядеть и атаковать. Будет логично сделать новый объект потомком объекта monster. Проанализировав код методов этого объекта, переопределим только те, которые реализуются по-другому ( пример 7.1).

type daemon = object (monster)
        procedure init(x_, y_, health_, ammo_, magic_ : word);
        procedure attack;
        procedure draw;
        procedure erase;
        procedure wizardry;
private
        magic : word;
end;
{ ------------------------- реализация методов объекта daemon ----------------- }
procedure daemon.init(x_, y_, health_, ammo_, magic_ : word);
begin
    inherited init(x_, y_, health_, ammo_);
    color := green;
    magic := magic_;
end;
procedure daemon.attack; { --------------------------------- daemon.attack ---- }
begin
    if ammo = 0 then exit;
    dec(ammo);
    if magic > 0 then begin
        outtextXY(x + 15, y, 'БУ-БУХ!'); dec(magic); end
    else 
        outtextXY(x + 15, y, 'бу-бух!');
end;
procedure daemon.draw;   { ----------------------------------- daemon.draw ---- }
begin 
    setcolor(color); outtextXY(x, y, '%)'); 
end;
procedure daemon.erase; { ----------------------------------- daemon.erase ---- }
begin 
    setcolor(black); outtextXY(x, y, '%)'); 
end;
procedure daemon.wizardry; { -------------------------------- daemon.wizardry - }
begin
    if magic = 0 then exit;
    outtextXY(x + 15, y, 'крибле-крабле-бумс!'); dec(magic);
end;
Листинг 7.1. Переопределение методов после добавления нового типа персонажей

Наследование полей.Унаследованные поля доступны в объекте точно так же, как и его собственные. Изменить или удалить поле при наследовании нельзя.Объект daemon содержит все поля своего предка и одно собственное поле magic, в котором хранится "магическая сила" объекта.

Наследование методов.В потомке объекта можно не только описывать новые методы, но и переопределять существующие. Метод можно переопределить либо полностью, либо дополнив метод предка.

В объекте daemon описан новый метод wizardry, с помощью которого объект применяет свою магическую силу, а метод инициализации init переопределен, потому что количество полей объекта изменилось. Однако необходимость задавать значения унаследованным полям осталась, и соответствующий метод есть в объекте monster, поэтому из нового метода инициализации сначала вызывается старый, а затем выполняются дополнительные действия (присваивание значения полю ammo ).

Вызов метода предка из метода потомка выполняется с помощью ключевого слова inherited (унаследованный). Можно вызвать метод предка и явным образом с помощью конструкции monster.init.

Методы отрисовки draw и erase также переопределены, потому что изображение демона отличается от изображения монстра и, следовательно, формируется другой последовательностью подпрограмм (для простоты представим демона в виде "смайлика").

Переопределен и метод attack: теперь атака выполняется по-разному в зависимости от наличия магической силы.

Чтобы перемещать демона, требуется выполнить те же действия, что записаны в методе move для перемещения монстра: необходимо стереть его изображение на старом месте, обновить координаты и нарисовать на новом месте. На первый взгляд, можно без проблем унаследовать этот метод, а также метод hit. Так мы и поступим.

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

program test_inheritance;
uses graph, crt, monsters;
var Vasia  : daemon;
    gd, gm : integer;
begin
    gd := detect; initgraph(gd, gm, '...');
    if graphresult <> grOk then begin
        writeln('ошибка инициализации графики'); exit end;
    Vasia.init(100, 100, 20, 10, 6); 
    Vasia.draw; Vasia.attack;
    readln;
    Vasia.erase; 
    readln;
end.

И в предке, и в потомке есть одноименные методы. Вызывается всегда тот метод, который соответствует типу объекта, потому что при вызове указывается имя экземпляра заданного типа ( рис. 7.1). Это можно рассматривать как простейший вид полиморфизма.

Раннее связывание

Рис. 7.1. Раннее связывание

< Лекция 6 || Лекция 7: 12345
София Шишова
София Шишова

Я завершила экзамен 90 баллов на 5. Сертификат не заказала. Сейчас пытаюсь найти как его заказать. у меня указано экзамен пройден баллы оценка видно, а чтоб заказать сертификат нигде не видно.