Перегрузка методов представляет собой достаточно простой механизм, но при его использовании все же есть ряд особенностей, которые необходимо учитывать.
· При перегрузке виртуального метода следует использовать ключевое слово reintroduce. В противном случае компилятор выдаст предупреждение о том, что перекрывается динамический метод.
Например:
Tl = class (TObject)
procedure Test (I: Integer); overload; virtual;
end;
T2 = class (Tl)
procedure Test (I: Integer); reintroduce; overload;
End; S : String
· Нельзя перегружать метод в разделе published объявления объекта. Например, недопустимо следующее объявление:
Tl = class (TMyObject)
Published
procedure Test (I: integer); procedure Test (S: string); •nd;
В то же время можно перекрывать метод в разделе published, если эт происходит на разных уровнях иерархии. Например: Tl = class published
procedure Test (I: integer); end;
T2 = class (Tl); published
procedure Test (S: string); end;
3. При перегрузке методов необходимо учитывать возможность возникновен] неоднозначных вызовов перегруженных методов, например, при использовании в перегружаемых методах параметров по умолчанию.
Вызов переопределенного метода родительского класса (inherited) При реализации метода, переопределенного любым способом в классе'? наследнике (переопределенного статического метода, перекрытого виртуальког или динамического метода - override, перегруженного метода - overload), остается возможность вызвать перекрытый метод класса родителя. Для этого перед именем метода при его вызове ставится ключевое слово inherite' Например:
inherited Create (...) ;
вызывает метод Create родителя.
Если записать слово inherited и после него не писать имя вызываемого метода, то будет вызываться наследуемый метод, совпадающий по имени с именем того метода, из которого он вызывается. Например, если написать! inheri ted в конструкторе, то вызовется конструктор родительского класса.
§3.10. Указатели на методы. События
Очень важной конструкцией языка Object Pascal является тип данных указателя на метод. С технической точки зрения, это процедурный тип данны: со скрытым параметром self. Переменная типа указатель на метод содержи два адреса: адрес кода метода и адрес экземпляра объекта, который появляется в коде метода как неявный параметр self.
Описание типа указатель на метод выглядит как описание обычног процедурного типа с добавленными в конце ключевыми словами of object.
Например, описание процедурного типа: type IntProceduralType = procedure (Num : integer);
Описание типа указатель на метод: type IntMethodPointerType = procedure (Num : integer) of object; Поля такого типа можно использовать в объектах.
type
MyClass = class Value : Integer;
Operation : IntMethodPointerType and;
Полю Operation можно присвоить любой совместимый метод - такого же вида (процедура или функция) и с таким же набором параметров, для метода- функции должен совпадать также тип возвращаемого результата. Например, можно написать еще один класс, у которого есть метод с целочисленным
параметром: type
AnotherClass = class X : Integer;
procedure Add (N: Integer);
end ;
Если определить объекты этих двух классов, например:
var
MyObject : MyClass; AnothorObject : AnotherClass;
то после инициализации объектов можно сделать такое присваивание:
MyObject.Operation := AnotherObject.Add;
если после этого вызвать методMyObject.Operation, то в действительности произойдет вызов методаAdd объектаAnotherOb ject.
Такая техника является краеугольным камнем компонентной технологии Delphi, поскольку позволяет реализовать технологию делегирования. Если написан (и даже скомпилирован) объект, у которого есть поля в виде указателей на методы, то можно легко изменить их поведение, просто присваивая этим
указателям новые методы.
Например, когда добавляется событие OnClick для кнопки, Delphi
присваивает свойству кнопки с именемOnClick (типа указатель на метод) имя метода формы, который является обработчиком указанного события. Таким образом, при нажатии на кнопку, выполняется код данного обработчика события, даже если он описан внутри совершенно другого класса (класса формы обычно).
Такое делегирование можно осуществить и в тексте программы. Пример с присваиванием обработчику события щелчка кнопки метода проектируемой формы упрощенно можно Представить следующим образом. В Delphi определен типTNotifyEvent - указатель на метод. В классеTButton определено свойствоOnClick типаTNotifyEvent (на самом деле это свойство определено в одном из классов-родителей классаTButton, что для данного примера
несущественно), type
TNotifyEvent = procedure (Sender: TObject) of object;
TButton = class(TButtonControl)
private
FOnClick: TNotifyEvent; public
property OnClick: TNotifyEvent read FOnClick write FOnClick; end;
Теперь, если в форме описать метод, подходящий к типуTNotifyEvent (то есть процедуру с одним параметром типаTObject).
MyClassRef = class of MyClass;
Далее можно определять переменные обоих типов:
Var
AClassRef : MyClassRef; AnObject : MyClass;
Ссылки на класс используют для изменения типа класса во время выполнения
Ссылки на класс можно использовать во всех выражениях, где допустим
использование типа данных. Таких выражений не так уж много, но есть несколько
интересных случаев. Простейший из них - создание объекта. Например: AClassRef := MyClass;
AnObject := AClassRef.Create;
Ссылки на класс напоминают концепцию метакласса, присутствующую в
некоторых других объектно-ориентированных языках. Однако в Object Pascal
ссылка на класс не является классом; она является всего лишь указателем на тип.
Так что аналогия с метаклассами (классами, описывающими другие классы) не совсем верна.
Ссылки на класс не были бы так полезны, если бы не поддерживали то же
правило совместимости типов, что используется и для обычных классов.
Определяя переменную-ссылку на класс, такую как MyClassRef можно
присвоить ей как родной класс, так и все его подклассы. Delphi определяв множество ссылок на классы в библиотеках VCL и RTL.
TClass = class of TObject; ExceptClass = class of Exception; TComponentClass = class of TComponent; TControlClass = class of TControl; TFormClass = diasa of TForm;
Глава 4. КОМПОНЕНТЫ DELPHI
§4.1. Палитра компонентов Delphi
Компоненты Delphi представлены на . палитре компонентов (описание см. §1.3). Страницы палитры компонентов группируют компоненты по типам.
Различные версии Delphi имеют отличающиеся палитры компонентов (рис.4.1-4.4).
Классическими (переходящими из версии одной версии Delphi в другую) можно назвать следующие страницы палитры компонентов (табл. 4.1 ).
Таблица 4.1
Название страницы | Описание |
Standard | Содержит наиболее распространенные, базовые компоненты, такие как главное меню, метка, поле ввода, кнопка и т.д. |
Additional | Является расширением страницы Standard, содержит часто используемые компоненты, или компоненты-модификации компонентов страницы Standard, например: кнопки с рисунком, для панели инструментов, маскированное поле ввода, таблицы строк, изображений, рисунок и т.д. |
Win32 | Включает элементы управления, присущие 32-разрядной версии Windows, например страница с закладками, анимированное изображение, перемещаемая панель инструментов, дерево и т.д. |
System | Содержит компоненты для доступа к объектам операционной системы, например, таймер, медиаплейер. окно рисования, контейнер OLE- объекта, механизмы обмена DDE |
Dialogs | Представлены компоненты, реализующие стандартные диалоги Windows. |
WLn3.1 | Включает элементы управления, присущие 16-разрядной версии Windows |
Data Access | Содержит компоненты, определяющие доступ к базам данных |
описывает все классы, а его листья (а также отдельные ветви нижних уровней) i являются классами тех компонентов, которые представлены на пшшгЩ компонентов, например, класс обычной кнопкиTButton.
Таким образом, рассматривая свойства и методы классов-предков компонентов(TObject, TPersistent, TComponent, TControl), можнорассмотреть все общие свойства и методы компонентов. Упрощенная иерархи классов - предков компонентов Delphi представлена на рис. 4.5.
Рис. 4.5. Иерархия классов-предков компонентов Delphi
Работа с иерархией объектов VCL осуществляется с помощью инструментА-
Browser, который может быть вызван командой главного менюView->Browser
или быстрыми клавишамиShJ f t+Ctrl+B. В частности по этой иерархии можн установить, что компонент TButton является наследником клас TButtonControl, который имеет своим предком классTWinControlкоторый происходит от классаTControl и т.д. Следовательно, зная свойстваиметоды классовTWinControl, TControl и т.д., можно предполагать каки свойства и методы есть у кнопки.
Классы компонентов, как и всё классы Delphi, происходят от классаTObject
и от него получают методы для создания и уничтожения себя в оперативной памяти и т.д.
Следующим классом, от которого происходят все классы компонентов,икоторый происходит непосредственно отTObject, является кла- TPersistent. Он обеспечивает своих потомков возможностью взаимодействовать с другими объектами.В частности, классTPersistentпередает своим потомкам виртуальный методAssign.
procedure Assign (Source: TPersistent);
С помощью этого метода поля и свойства объектаSource копируются в объект, вызвавший методAssign. Если описаны два объектаObjl иObj2классов-наследниковTPersistent, то записи Objl Obj2; // присваивание Objl.Assign (Obj?); // копирование
имеют совершенно разный смысл. Если в первом случае переменная-объектObjl(по сути указатель) начинает указывать на другой экземпляр объекта, то во втором случае происходит копирование полей из экземпляра объектаObj 2 в экземпляр объектаObj 1 (рис.4.6).
Рис.4.6. Различие выполнения операции присваивания и методаAssign
Таким образом, с помощью полиморфизма обмениваться данными между собой могут все наследники классаTPersistent. КлассTPersistent никогда не используется напрямую, от него порождаются потомки, которые должны уметь передавать другим объектам значения своих свойств.
Следующим классом в рассматриваемой иерархии стоит классTComponent.В нем инкапсулированы самые общие свойства и методы компонентов. Класс TComponent служит базой для создания как видимых, так и невидимых компонентов. Классы невизуальных компонентов можно создавать как непосредственных наследников этого класса. Механизмы, реализованные в классе TComponent, обеспечивают взаимодействие компонента со средой разработки (Палитрой компонентов и Инспектором объектов).
КлассTControl происходит отTComponent и описывает общие свойства и методы видимых компонентов. Два наследника этого классаTWinControl и TGraphicControl - определяют соответственно две группы компонентов
имеющих оконный ресурс (способных получать и обрабатывать сообщения Windows) и не имеющих этого ресурса.
Оконный компонент в момент своего создания обращается к Windows с требованием выделения оконного ресурса и, если требование удовлетворяется- получает так называемый дескриптор окна. КлассTWinControl и его потомки хранят дескриптор окна в свойствеHandle. Программист может использовать этот дескриптор для непосредственного обращения к функциям API Windows. ПотомкиTGraphicControl не требуют от Windows дефицитного оконного ресурса, но они и не могут обрабатывать сообщения Windows - управляет такими компонентами оконный компонент-владелец (например, форма), который и является посредником между Windows и неоконными компонентами.
На основе классаTWinControl создан ряд дополнительных классов, например:TCustomControl, TScrollingWinControl и пр.В частности, свойства и методы классовTCustomControl иTGraphicControlобеспечивают компоненты дополнительными возможностями по рисованию графики на канве.