Компоненты и область действия
Объектовые типы
Цель работы:Изучение объектовых типов и свойств переопределения.
Краткие теоретические сведения
Объектовый тип является структурой, состоящей из фиксированного числа компонентов. Каждый компонент является либо полем, содержащим данные строго определенного типа, либо методом, выполняющим операции над объектом. По аналогии с описанием переменных, описание поля указывает тип данных этого поля и идентификатор, именующий поле: по аналогии с описанием процедуры или функции, описание метода указывает заголовок процедуры, функции, конструктора или деструктора.
Объектовый тип может наследовать компоненты другого объектового типа. Если T2 наследует от T1, то T2 является потомком T1, а T1 является родителем T2(Свойство переопределения).
Наследование является транзитивным, то есть если T3 наследует от T2, а T2 наследует от T1, то T3 наследует от T1. Область (домен) объектового типа состоит из него самого и из всех его наследников.
Объектовый тип object
наследо список
вание полей
end
; список методов
Наследование ( идентификатор типа объекта )
Список полей список идентификатора : тип ;
Список методов заголовок метода ;
; virtual
целочисленная константа
Заголовок метода заголовок процедуры
заголовок функции
заголовок конструктора
заголовок деструктора
Следующий исходный код приводит пример описания объектового типа. Далее во всем этом методическом пособии вы найдете ссылки на данное описание.
Type
Point = object
X, Y: integer;
End;
Rect = object
A, B: Point;
procedure Init(XA, YA, XB, YB: integer);
procedure Copy(var R: Rect);
procedure Move(DX, DY: integer);
procedure Grow(DX, DY: integer);
procedure Intersect(var R: Rect);
procedure Union(var R: Rect);
function Contains(P: Point): boolean;
End;
StringPtr = ^string;
FieldPtr = ^Field;
Field = object
X, Y, Len: integer;
Name: StringPtr;
constructor Copy(var F: Field);
constructor Init(FX, FY, FLen: integer; FName: string);
Destructor Done; virtual;
Procedure Display; virtual;
Procedure Edit; virtual;
function GetStr: string; virtual;
function PutStr(S: string): boolean; virtual;
End;
StrFieldPtr = ^StrField;
StrField = object(Field)
Value: StringPtr;
constructor Init(FX, FY, FLen: integer; FName: string);
Destructor Done; virtual;
function GetStr: string; virtual;
function PutStr(S: string): boolean;
Virtual;
function Get: string;
procedure Put (S: string);
End;
NumFieldPtr = ^NumField;
NumField = object(Field)
Value, Min, Max: integer;
constructor Init(FX, FY, FLen: integer; FName: string;
FMin, FMax: longint);
function GetStr: string; virtual;
function PutStr(S: string): boolean;
Virtual;
function Get: longint;
function Put(N: longint);
End;
ZipFieldPtr = ^ZipField;
ZipField = object(NumField)
function GetStr: string; virtual;
function PutStr(S: string): boolean; virtual;
End;
В отличие от других типов, объектовые типы могут описываться только в разделе описаний типов, находящемся на самом внешнем уровне области действия программы или модуля. Таким образом, объектовые типы не могут описываться в разделе описаний переменных или внутри блока процедуры, функции или метода.
Компоненты и область действия
Тип компоненты файлового типа не может иметь объектовый тип или любой структурный тип, содержащий компоненты объектового типа.
Область действия идентификатора компоненты простирается за пределы домена его объектового типа. Более того, область действия идентификатора компонента простирается сквозь блоки процедур, функций, конструкторов и деструкторов, которые реализуют методы объектового типа и его наследников. Исходя из этих соображений, написание идентификатора компоненты должно быть уникальным внутри объектового типа и внутри всех его наследников, а также внутри всех его методов.
Область действия идентификатора компонента, описанного в части private описания типа, ограничивается модулем (программой), которая содержит описание объектового типа. Другими словами, частные (private) компоненты-идентификаторы действуют, как обычные общедоступные идентификаторы в рамках модуля, который содержит описание объектового типа, а вне модуля любые частные компоненты и идентификаторы неизвестны и недоступны. Поместив в один модуль связанные типы объектов, можно сделать так, что эти объекты смогут обращаться к частным компонентам друг друга, и эти частные компоненты будут неизвестны другим модулям.
Методы
Описание метода внутри объектового типа соответствует опережающему описанию метода (forward). Таким образом, где-нибудь после описания объектового типа, но внутри той же самой области действия, что и область действия объявления объектового типа, метод должен реализоваться путем определения его описания.
Если требуется уникальный идентификатор метода, то используется уточненный идентификатор метода. Он состоит из идентификатора типа объекта, за которым следуют точка и идентификатор метода. Как и любому другому идентификатору, идентификатору уточненного метода, если требуется, могут предшествовать идентификатор пакета и точка.
Внутри описания объектового типа в заголовке метода могут указываться параметры описываемого объектового типа, даже если описание еще не завершено. Это иллюстрируется методами Copy, Intersect и Union типа Rectпредыдущего примера.
Виртуальные методы
По умолчанию, методы являются статическими, однако могут, за исключением конструкторов, быть виртуальными (посредством включения директивы virtual в описание метода). Компилятор разрешает ссылки на вызовы статических методов во время процесса компиляции, тогда как вызовы виртуальных методов разрешаются во время выполнения. Это иногда называют поздним связыванием.
Если объектовый тип объявляет или наследует какой-либо виртуальный метод, то переменные этого типа должны быть инициализированы посредством вызова конструктора перед вызовом любого виртуального метода. Таким образом, объектовый тип, который описывает или наследует виртуальный метод, должен также описывать или наследовать по крайней мере один метод-конструктор.
Объектовый тип может переопределять любой из методов, которые он наследует от своих предков. Если описание метода в потомке указывает тот же идентификатор метода, что и описание метода в предке, то объявление в потомке подавляет объявление в предке. Область действия переопределяющего метода расширяется до сферы действия потомка, в котором этот метод был введен, и будет оставаться таковой, пока идентификатор метода не будет переопределен снова.
Переопределение статического метода не зависит от изменения заголовка метода. В противоположность этому, переопределение виртуального метода должно сохранять порядок, типы и имена параметров, а также типы результатов функций, если таковые имеются. Более того, переопределение опять же должно включать директиву virtual.
Динамические методы
В Турбо Паскале для Windows вводится дополнительный класс методов позднего связывания, которые называются динамическими методами. Динамические методы отличаются от виртуальных методов только тем, как они вызываются на этапе выполнения. Во всех других отношениях динамический метод можно рассматривать, как эквивалентный виртуальному методу.
Описание динамического метода аналогично описанию виртуального метода, но описание динамического метода должно включать в себя индекс динамического метода, который указывается сразу за ключевым словом virtual. Индекс динамического метода должен задаваться целочисленной константой в диапазоне 1..65535 и представлять собой уникальное значение среди индексов динамического метода или других динамических методов, содержащихся в объектовом типе или его предках. Например:
Рrocedure FileOpen(var Msg: TMessage); virtual 100;
Переопределение динамического метода должны точно соответствовать порядку, типу и именам параметров и типу результата функции. Переопределение должно также включать в себя директиву virtual, за которой следует тот же индекс динамического метода, что и заданный в объектовом типе предка.