PCivil, Init(1995, 'Мария', 'Рыбкина', 12));
Persons[3]:= New(PMilitary, Init(1985, 'Андрей', 'Быков', 'Майор'));
{ В ходе распечатки вызывается метод ФАКТИЧЕСКОГО объекта }
for i:=1 to 3 do Persons[i]^.Report;
Readln;
end.
Сокрытие полей и методовОбъяснять ли вам, из чего строят современные программы? Из сотен «умных» объектов, которые образуют ветвистую иерархию родственных связей, открывающую простор полиморфизму.
Многие объекты фирменных библиотек – это полуфабрикаты, требующие лишь небольшой настройки под конкретное применение. В ходе такой настройки программист добавляет к базовому объекту свои поля и методы. И здесь порой случается то же, что при использовании библиотечных модулей: имя, назначенное программистом, может совпасть с уже объявленным именем в предке. И тогда имена могут конфликтовать. В библиотечных модулях эта проблема решается скрытием большей части переменных, процедур и функций в невидимой извне секции реализации IMPLEMENTATION.
Схожий прием используют и в объектном программировании. Поля и методы, доступ к которым наследникам не нужен, прячут в объекте-предке так, что они становятся невидимыми за пределами предка. И тогда спрятанные имена можно использовать в наследниках повторно по иному назначению. Не будет ли здесь путаницы? Нет, поскольку методы предка не знают о новых именах и обращаются к старым. А методы наследника не видят старых имен и обращаются к новым. Разумеется, что разработчик объекта-предка тщательно отбирает те поля и методы, что потребуются создателям потомков.
Сокрытие имен объекта организовано очень просто: в объявление объекта вставляют ключевые слова 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. Изучение этой и ей подобных библиотек – прекрасный способ освоения объектной технологии, подробное описание библиотеки можно найти в Сети и в литературе.
Итоги• Объектно-ориентированное программирование – это современная технология быстрой разработки крупных и надежных программ.
• Объект – это сложный тип данных, совмещающий в себе собственно данные и процедуры, обрабатывающие их.
• Объектно-ориентированное программирование основано на трех дополняющих друг друга механизмах: инкапсуляции, наследовании и полиморфизме.
• Инкапсуляция – это объединение данных и процедур, их обрабатывающих, в едином объекте.
• Наследование позволяет создавать новые типы объектов на базе существующих. Так создается иерархия родственных объектов.
• Полиморфизм состоит в схожем поведении объектов родственных типов.
А слабо?А) Разработайте иерархию «человечьих» объектов в соответствии со следующим рисунком (новые типы объектов выделены цветом).
Дайте новым типам объектов подходящие имена, дополните их надлежащими полями, переопределите конструкторы и метод Report. Затем исследуйте механизм полиморфизма на предке и всех его потомках.
Б) Мощность множеств в Паскале не превышает 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.
Глава 62Самое интересное только начинается!
Мы у финишной черты, где принято подводить итоги. Нет, друзья, повременим с итогами, ведь для вас все только начинается, – лучше обсудим ваши планы на будущее.
Крупицы мастерстваЧем зарабатывает программист? – создает программы. У хорошего мастера дело спорится, и товар его добротен. Как скорее достичь мастерства? За что браться, с чего начать? Вот несколько советов.
Постигайте языки программированияПервым делом хорошенько оседлайте Паскаль – один из лучших языков программирования. Даже школьник, владеющий Паскалем, – это наполовину инженер, ведь мощная система программирования Delphi построена на этом языке. Часть пути к вершинам Паскаля мы преодолели вместе, но освоили далеко не все его возможности. Дальше ступайте сами: преодолев робость и сомнения, откройте «взрослый» учебник по Паскалю, – некоторые из таких учебников найдете в списке рекомендуемой литературы. Там вас ждет немало открытий!
А что другие языки? Среди них отметим Си – один из самых используемых. Но почему не Паскаль?
Языки Паскаль и Си – ровесники, они родились в начале 70-х годов прошлого века. Паскаль был задуман как строгий язык для надежного программирования, но на первых порах применялся лишь в образовании. Создатели языка Си преследовали иную цель, – им срочно понадобился незатейливый язык для появившихся в ту пору мини-ЭВМ. Надо заметить, что программы, написанные на Паскале, эти слабенькие ЭВМ переваривали с трудом, а строгие ограничения надежного Паскаля по рукам и ногам вязали ретивых системщиков. Потому сработанный на скорую руку простенький и ненадежный