TURBO PASCAL

Новости

Программы   

Turbo Pascal 

Игры

Документация   

Странности

FAQ

Ссылки

Форум

Гостевая книга

Рассылка

Благодарности

Об авторе

 

 

ООП на Pascal'е:

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

 

Введение

 

Язык Pascal был создан задолго до того, как выяснилось, что ООП становится de facto стандарной концепцией разработки программного обеспечения. Соответственно, появившиеся реализации ООП подхода на Pascal'е несут в себе отпечаток дообъектного прошлого этого языка.

Лидер разработок компиляторов паскаля в Borland Андрес Хейлсберг (Andres Heilsberg) решил ввести элементы ООП лишь в версию (5.5), а следующие версии сделать полностью ООП-ориентированными. К сожалению, полностью это так и не удалось.

Синтаксис

 

Для того, чтобы объявить класс на Pascal'е необходимо воспользоваться ключевым словом Object (1). Так как класс всегда является типом, делать это можно лишь в Type части программы:

Type
Class1 = Object
{список полей}
A: Byte;
V: Real;
{список методов}
Procedure Nothing(Var K: Byte);
End;

Легко заметить, что поля и методы (общее для них название - члены класса) объявляются очень похоже на поля записи и обычные процедуры/функции. Объекты класса объявляются так же, как и обычные переменные:

Var Object1, Object2: Class1;

Соотвенно, доступ к полям объекта некоторого класса производится аналогично доступу к полям записи:

Object1.V:= Object2.A;

Обращение к методам класса производится аналогичным образом:

Object1.Nothing(Object1.A);

 

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

 

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

Type Class2 = Object(Class1)
M: Integer;
End;
Var Object3: Class2;

При таком объявлении объект Object3 обладает тремя полями - A, V, M - и одним методом - Nothing(Var Byte).

Методы

 

Методы объектов обладают единственным отличием от обычных процедур/функций: они, собственно, принадлежат объектам. Следовательно, они обладают доступом к полям именно "своему" объекту. Так как объектов в программе может быть множество, то, во избежание дублирования кода, каждый метод получает в качестве неявного параметра указатель на объект, для которого он вызван. Данный указатель доступен в теле метода как @Self. Естественно, что объявленный (декларированный) при определении класса метод должен быть определен (дефинирован) в программе. Делается это примерно следующим образом:

Procedure Class1.Nothing(Var K: Byte);
Begin
{body of method}
V:= K;
@Self^.V:= K;
End;

Третья и четвертая строки абсолютно идентичны. В сущности третья является лишь удобным сокращением второй.

Известно, что все методы класса делятся на обычные (статические) и виртуальные. Любой метод считается статическим, если не указано обратное. Указать же, что метод является виртуальным можно, указав после его декларации в дефиниции класса ключевое слово Virtual:

Type
Class3 = Object
Procedure Nothing(Var K: Byte); Virtual;
End;

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

Конструкторы и деструкторы

 

Среди всех методов класса выделяют две особых группы, имеющих особое значение при создании и удалении объектов этого класса:
конструкторы;
деструкторы.

 

Конструкторы предназначены для инициализации полей объектов в момент их создания. Объявляются они следующим образом:

Type Class4 = Object
B: Byte;
Constructor Init(CB: Byte);
Destructor Done; Virtual;
End;
Constructor Class3.Init(CB: Byte);
Begin
B:= VB;
End;
Destructor Class3.Done;
Begin
End;

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

Несмотря на то, что как конструктор, так и деструктор могут быть вызваны непосредственно, их специфическое назначение привело к появлению возможности вызова их параллельно с созданием/удалением объектов. Так как создание/удаление объектов в процессе выполнения программы на Pascal'е возможны только при использовании ДРП, то функции создания/удаления типизированных переменных имеют дополнительный синтаксис (см. соответствующий урок):

{ . . . }
Type
PClass4 = ^Class4;
Var P: PClass4;
{ . . . }
Begin
P:= New(PClass4, Init(4));
{ . . . }
Dispose(P, Done);
End;

Именно здесь мы впервые встретились с возможностью с помощью одной и той же переменной получить доступ к объектам различных классов. Действительно, в зависимости от хода алгоритма указателю P может быть присвоено значение адреса как объекта класса Class4, так и адреса объекта класса-наследника от Class4.

Перекрытие методов

 

Перекрыть метод предка в классе наследнике очень просто: продекларировать метод с тем же именем.

Type Class5 = Object(Class1)
Procedure Nothing;
End;

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

Выводы

 

Итак, в Borland Pascal v.7.0 реализованы все три основные принципа ООП и частично - механизм позднего связывания - он работает только при использовании указателей. Невозможность полной реализации связана с тем, что типы статических объектов (переменных) на Pascal'е определяются до выполнения программы, фактически еще до ее компиляции. Естественно, что для объектов предопределенного типа (класса) нет смысла применять механизм определения типа и вызова соответствующего метода (i.e. механизм позднего связывания).

(1) Обратно Это явное несоответствие, вероятно, связано с неустоявшейся терминологией в ООП на момент разработки синтаксиса. В более поздних реализациях Pascal'я для этой цели явно используется ключевое слово class.

 

На первую страницу

Rambler's Top100 Rambler's Top100
PROext: Top 1000

(с)Все права защищены

По всем интересующим вопросам прошу писать на электронный адрес

Hosted by uCoz