Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
delphi / песни о паскале.pdf
Скачиваний:
59
Добавлен:
26.03.2016
Размер:
5.16 Mб
Скачать

Глава 61 «Кубики» программиста (ООП)

{--- Реализация объекта «ГРАЖДАНСКИЙ СЛУЖАЩИЙ» ---}

constructor TCivil.Init(aBearing: integer; const aName, aFam : string;

begin

 

aLevel: integer);

 

 

inherited Init(aBearing, aName, aFam);

 

mLevel:= aLevel;

 

end;

 

 

procedure TCivil.Report;

 

begin

 

 

inherited Report;

 

Writeln('Категория: ', mLevel);

 

end;

 

 

var Persons : array[1..3] of PPerson;

{ массив указателей на ПРЕДКА }

i : integer;

 

begin

{--- Главная программа ---}

 

{Массив заполняется объектами РАЗНЫХ, но родственных типов } Persons[1]:= New(PPerson, Init(1985, 'Иван', 'Семенов')); Persons[2]:= New(PCivil, Init(1995, 'Мария', 'Рыбкина', 12)); Persons[3]:= New(PMilitary, Init(1985, 'Андрей', 'Быков', 'Майор'));

{В ходе распечатки вызывается метод ФАКТИЧЕСКОГО объекта }

for i:=1 to 3 do Persons[i]^.Report;

Readln;

end.

Сокрытие полей и методов

Вы догадываетесь, из чего строят современные программы? Из сотен «умных» объектов, образующих ветвистую иерархию родственных связей, которая открывает простор полиморфизму.

Многие объекты фирменных библиотек — это полуфабрикаты, требующие лишь небольшой настройки под конкретное применение. В ходе такой настройки программист добавляет к базовому объекту свои поля и методы. И здесь порой случается то же, что при использовании библиотечных модулей: имя, назначенное программистом, может совпасть с уже объявленным именем в предке. И тогда имена могут конфликтовать. В библиотечных модулях эта проблема решается скрытием большей части переменных, процедур и функций в невидимой извне секции реализации IMPLEMENTATION.

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

516

Глава 61 «Кубики» программиста (ООП)

становятся невидимыми за пределами предка. И тогда спрятанные имена можно использовать в наследниках повторно по иному назначению. Не будет ли здесь путаницы? Нет, поскольку методы предка не знают о новых именах и обращаются к старым. А методы наследника не видят старых имен и обращаются к новым. Разумеется, что разработчик объекта-предка тщательно отбирает те поля и методы, которые потребуются создателям потомков.

Сокрытие имен объекта организовано очень просто: в объявление объекта вставляют ключевые слова PRIVATE (личный) и PUBLIC (общедоступный). Эти слова разбивают объявление объекта на две части — приватную и общедоступную, например:

type TParent = object

{ объект-предок }

private

 

A, B : integer;

 

function Calc(arg: integer): integer; public

Constructor Init(a, b : integer) function GetSum: integer; virtual;

end;

Здесь поля A и B, а также функция Calc, скрыты от взоров потомков. Поэтому программист, импортировавший объект типа TParent, может спокойно добавить в него свои поля или методы с теми же самыми именами, например, так:

type TChild = object (TParent)

{ объект-наследник }

A, B : string;

procedure Calc;

. . .

end;

Здесь в потомке поля A и B имеют другой тип, а имя Calc принадлежит не функции, а процедуре. Но поля и методы предка с этими же именами всё ещё существуют! Но доступны только предку, вот и всё.

А если в объявлении объекта не указаны ключевые слова PRIVATE и PUBLIC? Тогда все его поля и методы по умолчанию будут общедоступными.

Итак, мы рассмотрели идеи и механизмы, лежащие в основе объектноориентированного программирования. К сожалению, одной главы маловато для освоения всех тонкостей этой технологии — на то есть другие книги. Объектные технологии — это настоящее и будущее программирования, не жалейте времени на их освоение. Здесь, как и во всем, важна практика. В начале главы я дал пример использования библиотеки Turbo Vision. Изучение этой и ей подобных библиотек

517

Глава 61 «Кубики» программиста (ООП)

— прекрасный способ освоения объектной технологии, подробное описание библиотеки можно найти в Сети и в литературе.

Итоги

Объектно-ориентированное программирование – это современная технология быстрой разработки крупных и надежных программ.

Объект – это сложный тип данных, совмещающий в себе собственно данные и процедуры, обрабатывающие их.

Объектно-ориентированное программирование основано на трех дополняющих друг друга механизмах: инкапсуляции, наследовании и полиморфизме.

Инкапсуляция – это объединение данных и процедур, их обрабатывающих, в едином объекте.

Наследование позволяет создавать новые типы объектов на базе существующих. Так создается иерархия родственных объектов.

Полиморфизм состоит в схожем поведении объектов родственных типов.

Аслабо?

А) Разработайте иерархию «человечьих» объектов в соответствии со следующим рисунком (новые типы объектов выделены цветом).

TPerson

 

TMilitary

 

 

 

Ребенок

 

 

 

TCivil

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Танкист

 

 

 

Моряк

 

 

 

Авиатор

 

 

 

Учитель

 

 

 

Врач

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Дайте новым типам объектов подходящие имена, дополните их надлежащими полями, переопределите конструкторы и метод Report. Затем исследуйте механизм полиморфизма на предке и всех его потомках.

518

Глава 61 «Кубики» программиста (ООП)

Б) Мощность множеств в Паскале не превышает 256, и часто этого бывает недостаточно. Сконструируем свой тип множеств, назовем его TBigSet, мощность которого составит 65536 (соответствует диапазону для типа Word). Оформим это множество как объект.

type

 

TSetArray = array [0..4096] of word;

{ хранит 65536 бит (4096*16) }

PSetArray = ^ TSetArray;

{ тип-указатель на массив }

TBigSet = object

mArray : PSetArray; { указатель на динамический массив } Constructor Init; { создает динамический массив mArray ) Destructor Done; { освобождает память, занятую массивом } procedure ClearAll; { опустошает множество }

procedure SetAll; { делает множество полным }

procedure Insert(N); { вставляет элемент N в множество } procedure Delete(N); { удаляет элемент N из множества }

function Member(N):Boolean; { проверяет принадлежность N к множеству } function IsEmpty:Boolean; { проверяет пустоту множества }

procedure Union(BS: TBigSet); { добавляет другое множество } procedure InterSect(BS: TBigSet); { формирует пересечение множеств } procedure Load(var F: text); { вводит множество из файла } procedure Save(var F: text); { выводит множество в текстовый файл }

end;

Примените здесь сведения из главы 48, а также идеи из задачи 49-В (глава 49). Так, включение в множество и исключение из него элемента N может быть выполнено установкой и сбросом бита в массиве mArray^.

mArray^[N div 16]:= mArray^[N div 16] or (1 shl (N mod 16)) mArray^[N div 16]:= mArray^[N div 16] and not (1 shl (N mod 16))

Объединение с другим множеством Union(BS:TBigSet) можно сделать логическим суммированием массивов:

for I:=0 to 4095 do mArray^[ I ]:= mArray1^[ I ] or BS.mArray^[ I ]

И так далее. Напишите реализацию всех методов объекта и примените его к решету Эратосфена и прочим задачам из главы 38.

519

Соседние файлы в папке delphi