Студопедия КАТЕГОРИИ: АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Тип interface в Object Pascal
В языке Object Pascal начиная с версии Delphi 3 за ключевым словом interface, которое прежде использовалось только для объявления начала интерфейсной секции модуля unit, было закреплено еще одно значение – имя типа, более всего подобного типу class. В этом значении термин interface является краеугольным камнем технологии COM (Component Object Model – модель компонентных объектов). В этом разделе мы еще не будем касаться собственно технологии COM, а разберемся с тем, как можно использовать этот тип в программе и какую пользу из этого можно извлечь. Если обратиться к описанию языка Object Pascal, то в нем приведен такой формат описания типа interface: Type имя_типа = interface (интерфейс-предок) ['{GUID}'] описание компонент end;
Как видно из приведенного формата, описание типа interface очень похоже на описание типа class. Пропустим пока обсуждение фрагмента описания ['{GUID}'] и оговорим правила описания интерфейса:
Смысл и назначение интерфейса в Object Pascal наиболее близки к понятию абстрактного класса. Вот абстрактный пример абстрактного класса: Type TAbstractClass = class Procedure MyProc(Src : string); virtual; abstract; end;
Какова цель описания абстрактного класса? Такой класс является базой для создания классов наследников и декларирует их свойства и поведение, но не содержит конкретную реализацию этого поведения. Другими словами, абстрактный класс служит своего рода декларацией о намерениях, а его наследники должны эти намерения воплотить в жизнь путем реализации заявленных абстрактных методов.
Простейший пример использования типа Interface в программе. Создадим типовое приложение и добавим в него описание таких классов и их реализацию: Type TForm1 = class(TForm) Button1: TButton; Procedure Button1Click(Sender: TObject); end; ITest = interface ['{226FEB40-E9ED-11D7-846C-C1A00994643B}'] {не обязательно} Procedure Beep; end; TTest = class (TInterfacedObject,ITest) Procedure Beep; Destructor Destroy; override; end; Var Form1: TForm1; Implementation {$R *.dfm} Procedure TTest.Beep; Begin Windows.Beep(2000,500); End; Procedure TForm1.Button1Click(Sender: TObject); var Test : ITest; Begin Test:=TTest.Create; Test.Beep; End; Destructor TTest.Destroy; Begin ShowMessage('Destroy was called'); inherited; End; END. Прежде всего отметим, что описание класса ITest несколько отличается от описания «обычного» класса тем, что в нем присутствует GUID (его значение в Delphi генерируется с помощью клавишной команды Ctrl+Shift+G), хотя в данном примере его можно было бы и опустить. Вторая особенность класса ITest заключается в том, что метод Beep в нем просто декларируется, а реализация этого метода должна быть выполнена в другом классе. У описания класса TTest также есть особенность: два «родителя». Такое в Object Pascal возможно только в том случае, когда дополнительный порождающий класс имеет тип интерфейс и базовым классом является также класс TInterfacedObject. Класс TInterfacedObject служит простым и удобным базовым классом, так как он содержит реализацию трех базовых методов интерфейса IInterface: QueryInterface, AddRef и Release. Вот описание этого класса: TInterfacedObject = class(TObject, IInterface) protected FRefCount: Integer; function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; public procedure AfterConstruction; override; procedure BeforeDestruction; override; class function NewInstance: TObject; override; property RefCount: Integer read FRefCount; end;
При запуске приложения на выполнение можно заметить еще одну особенность – автоматический вызов деструктора класса TTest в тот момент, когда локальная переменная Test перестает существовать при завершении процедуры Button1Click. В режиме пошагового выполнения программы (при включенном режиме Project Options►Compiler►Use debug DCUs) можно заметить, что вызов деструктора выполняет метод TInterfacedObject._Release, который в свою очередь вызывается функцией System._IntfClear. Приведенный пример приложения показывает, между прочим, как можно в Object Pascal добиться автоматического вызова деструктора (как в С++). Отметим также, что класс, производный от TInterfacedObject, может включать произвольное число интерфейсов, а не только один, как в приведенном примере. Процедура Button1Click может быть реализована и таким образом: Procedure TForm1.Button1Click(Sender: TObject); var Test : TTest; IObj : ITest; Begin Test:=TTest.Create; if Test.GetInterface(ITest,IObj) then IObj.Beep else ShowMessage('Интерфейс ITest не поддерживается'); End;
В этом варианте показано, как можно проверить наличие интерфейса ITest с помощью метода TObject.GetInterface, который возвращает значение true в случае наличия запрашиваемого интерфейса и false – в противном. При этом, однако, в описании интерфейса ITest обязательно наличие GUID: если его не будет, то компилятор выдаст сообщение об ошибке. Несмотря на то, что первый параметр метода GetInterface объявлен как имеющий тип TGuid, вместо него можно передавать имя класса, содержащего описание запрашиваемого интерфейса. Возникает естественный вопрос: какова практическая польза от класса TInterfacedObject, если не считать предоставляемой им возможности автоматического вызова деструктора? Все зависит от фантазии программиста. Например, с помощью этого средства можно обеспечить единообразное взаимодействие нескольких классов приложения, например, форм, если каждый из этих классов будет включать один и тот же общий интерфейс и собственную реализацию всех или некоторых методов этого интерфейса (см. раздел «Использование интерфейсов внутри программы» в работе «Delphi6 и технология COM»). Другой пример – реализация модулей расширения программы (plug-ins) из той же работы.
33. Пример реализации и использования COM класса в С++ В этом разделе рассматривается весь процесс создания локального СОМ объекта, реализованного непосредственно в приложении. Этот пример построен по мотивам подобного примера из работы: Роберт Дж. Оберг. Технология COM+. Основы и программирование.: Пер. с англ. :Уч. пос. – М.: Издательский дом "Вильямс", 2000. – 480с.
Одним из китов СОМ технологии является базовый интерфейс IUnknown, точнее, его спецификация. Реализация методов этого интерфейса отдается на откуп программистам, хотя, конечно, любая уважающая себя среда разработки программ естественно имеет его реализацию, которой и можно в подавляющем большинстве случаев воспользоваться. Более того, реализация методов этого интерфейса включена в базовые классы многих библиотек. Приведенный ниже пример программы очень близок к тому, который рассмотрен в разделе «Тип interface в Object Pascal». Пример достаточно прост, но в нем, в отличие от «паскалевского» варианта, я привожу и реализацию методов базового интерфейса IUnknown. Описание класса IUnknown содержится в файле ..\VC98\Include\Unknwn.h и выглядит так: struct IUnknown { virtual HRESULT STDMETHODCALLTYPE QueryInterface( /* [in] */REFIID riid, /* [iid_is][out] */void __RPC_FAR *__RPC_FAR *ppvObject)=0 ; virtual ULONG STDMETHODCALLTYPE AddRef( void) =0; virtual ULONG STDMETHODCALLTYPE Release( void) =0; };
Смысл использованных в описании макросов следующий: HRESULT – тип long |
|||
Последнее изменение этой страницы: 2018-04-12; просмотров: 609. stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда... |