Программирование - это просто
Advertisement
Главная arrow Уроки программирования arrow Пишем на Delphi с применением COM-технологий arrow Программирование COM в Delphi. Урок 4. Использование интерфейсов.
29.05.2024 г.
Главное меню
Главная
Интернет магазин
Программные продукты
Биржевые роботы
Искусственный интеллект
Математика и информатика
1С:Предприятие
Уроки C#
Уроки Delphi
Уроки программирования
Web-программирование
Дизайн и графика
Компьютер для блондинок
Исходники
Статьи
Платный раздел
Рассказы про компьютеры
Хитрости и секреты
Системный подход
Размышления
Наука для чайников
Друзья сайта
Excel-это не сложно
Все о финансах
.
Программирование COM в Delphi. Урок 4. Использование интерфейсов. Печать E-mail
Автор megabax   
27.08.2011 г.
New Page 1

Программирование COM в Delphi. Урок 4. Использование интерфейсов.

Исходники к уроку можно скачать здесь

Сегодня мы разберем простой пример использования интерфейсов. Пусть перед нами стоит задача разработать библиотеку для конвертации в строку различных типов данных. Начнем программирование этой библиотеки с создания интерфейса:

   IFormattedNumber = interface

      ['{384F6D44-53B8-4BF4-8EB0-5DC07E34D2D1}']

      function FormattedString:string;

      function GetName:string;

   end;

 

На основании этого интерфейса объявим классы для конвертации числа в строку в виде обычно числа и в виде шестнадцатеричного кода:

 

   TFormattedInteger = class(TInterfacedObject, IFormattedNumber)

   private

      FValue:integer;

   public

      constructor Create(AValue:integer);

      destructor Destroy; override;

      function FormattedString:string;

      function GetName:string;

   end;

 

   TFotmattedHexInteger = class(TFormattedInteger, IFormattedNumber)

   public

      destructor Destroy; override;

      function FormattedString:string;

      function GetName:string;

   end;

Теперь реализуем класс TFormattedInteger:

constructor TFormattedInteger.Create(AValue:integer);

begin

  inherited Create;

  FValue:=AValue;

end;

 

Destructor TFormattedInteger.Destroy;

begin

  FormInftDemo.MemoInftDemo.Lines.Add('TFormattedInteger.Destroy');

end;

 

Function TFormattedInteger.FormattedString:string;

begin

  Result:='The integer is '+IntToStr(FValue);

end;

 

Function TFormattedInteger.GetName:string;

begin

  Result:='TFormattedInteger';

end;

и TFFotmattedHexInteger:

destructor TFotmattedHexInteger.Destroy;

begin

  FormInftDemo.MemoInftDemo.Lines.Add('TFotmattedHexInteger.Destroy');

  inherited Destroy;

end;

 

function TFotmattedHexInteger.FormattedString:string;

begin

  result:='The hex is integer '+IntToHex(FValue,4);

end;

 

function TFotmattedHexInteger.GetName:string;

begin

  result:='TFotmattedHexInteger';

end;

А теперь займемся тестированием классов. Создадим вот такую форму*:

Программирование COM в Delphi. Урок 4. Использование интерфейсов.

По кнопочке btnAsObject мы тестируем создание объекта как объекта:

procedure TFormInftDemo.btnAsObjectClick(Sender: TObject);

var Inft:TFormattedInteger;

begin

   Inft:=TFotmattedHexInteger.Create(12);

   MemoInftDemo.Lines.Add(Inft.FormattedString);

   Inft.Free;

   MemoInftDemo.Lines.Add('End of procedure');

   MemoInftDemo.Lines.Add('');

end;

Посмотрим, как это работает:

Программирование COM в Delphi. Урок 4. Использование интерфейсов.

Возникает вопрос, почему у нас выскакивает TFormattedInteger.Destroy после TFotmattedHexInteger.Destroy? Все правильно, TFotmattedHexInteger объявлен как дочерний от TFormattedInteger. Уничтожая объект TFotmattedHexInteger мы вызывает его деструктор, а тот в свою очередь, вызывает деструктор TFormattedInteger. И еще у нас интересный вопрос, почему у нас число преобразуется в десятичный формат, а не в шестнадцатеричный? Ответ на него очень простой. Мы объявили переменную типа  TFormattedInteger, а метод FormattedString у нс не виртуальный, поэтому, независимо от того, что  присвоили мы объект TFotmattedHexInteger, у нас все равно будет вызываться FormattedString от класса FormattedString. Что бы исправить данную ошибку, достаточно метод FormattedString сделать виртуальным:

   TFormattedInteger = class(TInterfacedObject, IFormattedNumber)

   private

      FValue:integer;

   public

      constructor Create(AValue:integer);

      destructor Destroy; override;

      function FormattedString:string; virtual;

      function GetName:string;

   end;

 

   TFotmattedHexInteger = class(TFormattedInteger, IFormattedNumber)

   public

      destructor Destroy; override;

      function FormattedString:string; override;

      function GetName:string;

   end;

После этого мы увидим совершенно другую картину:

Программирование COM в Delphi. Урок 4. Использование интерфейсов.

На самом деле ошибка допущена умышленно, для чистоты эксперимента. Так что проверив, верните код "на место", сделав  FormattedString  снова не виртуальным.

Идем дальше. Попробуем объявить переменную типа IFormattedNumber и присвоить ей объект типа TFotmattedHexInteger (кнопочка btnAsInterfaceClick):

procedure TFormInftDemo.btnAsInterfaceClick(Sender: TObject);

var Inft:IFormattedNumber;

begin

   Inft:=TFotmattedHexInteger.Create(12);

   MemoInftDemo.Lines.Add(Inft.FormattedString);

   MemoInftDemo.Lines.Add('End of procedure');

   MemoInftDemo.Lines.Add('');

end;

И что же мы видим? Теперь работает правильно:

Программирование COM в Delphi. Урок 4. Использование интерфейсов.

Спрашивается, почему? Да потому, что при присваивании переменной интерфейсного типа какого либо объекта она автоматический принимает тип этого объекта.  Это все равно что написать что то в этом роде:

procedure TFormInftDemo.Button1Click(Sender: TObject);

var Inft:pointer;

begin

   Inft:=TFotmattedHexInteger.Create(12);

   MemoInftDemo.Lines.Add(TFotmattedHexInteger(Inft).FormattedString);

   MemoInftDemo.Lines.Add('End of procedure');

   MemoInftDemo.Lines.Add('');

end;

Кстати, заметьте, мы явно не вызываем деструктор объекта TFotmattedHexInteger, но он у нас все равно вызывается. Это связано с особенностью использования интерфейса: когда указатель на интерфейс больше не используется, связанный с ним объект автоматически уничтожается, путем вызова деструктора онного.  Аналогично будет уничтожаться объект, если интерфейсной переменной присвоить null:

procedure TFormInftDemo.btnExplicticDestroyClick(Sender: TObject);

var Inft:IFormattedNumber;

begin

   Inft:=TFotmattedHexInteger.Create(12);

   MemoInftDemo.Lines.Add(Inft.FormattedString);

   Inft:=nil;

   MemoInftDemo.Lines.Add('End of procedure');

   MemoInftDemo.Lines.Add('');

end;

Давайте запустим эту программу и убедимся в этом:

Программирование COM в Delphi. Урок 4. Использование интерфейсов.

Для следующих тестов нам понадобиться написать две функции, которые вставим как методы в главную форму программы:

procedure TFormInftDemo.ShowName(Inft:IFormattedNumber);

begin

   MemoInftDemo.Lines.Add(Inft.GetName);

End;

 

procedure TFormInftDemo.ShowNameConst(Const Inft:IFormattedNumber);

begin

   MemoInftDemo.Lines.Add(Inft.GetName);

End;

Теперь напишем программу, которая покажет имя создаваемых объектов:

procedure TFormInftDemo.btnFunctionClickClick(Sender: TObject);

var myInt:TFormattedInteger;

    myHexInft:IFormattedNumber;

begin

    MyInt:=TFormattedInteger.Create(27);

    ShowName(MyInt);

   // MyInt.Free;

    MyHexInft:=TFotmattedHexInteger.Create(2047);

    ShowName(MyHexInft);

end;

и протестируем ее:

Программирование COM в Delphi. Урок 4. Использование интерфейсов.

Если мы раскомментируем строчку:

   // MyInt.Free;

то произойдет исключительна ситуация (программа выдаст страшное сообщение)*:

Программирование COM в Delphi. Урок 4. Использование интерфейсов.

потому что к интерфейсу нельзя непосредственно применять деструктор - он вызывается автоматический. Может возникнуть вопрос, а с какой радости MyInt - интерфейс, когда эта переменная объявлена как TFormattedInteger? Все дело в том, что она передается в качестве параметра в функцию, у которой аргумент - интерфейс (IFormattedNumber). При такой передаче переменная приобретает свойство интерфейса. Об этой особенности следует помнить, если у вас есть процедуры или функции, которые в качестве аргумента используют интерфейсы.

Но если аргумент объявлен как const, (см. функцию ShowNameConst), то данный эффект не будет наблюдаться:

procedure TFormInftDemo.btnConstFunctionClickClick(Sender: TObject);

var myInt:TFormattedInteger;

begin

    MyInt:=TFormattedInteger.Create(27);

    ShowNameConst(MyInt);

    MyInt.Free;

end;

Давайте проверим:

Программирование COM в Delphi. Урок 4. Использование интерфейсов.

Исходники к уроку можно скачать здесь..


Скриншоты, помеченные знаком * , являются цитатами и иллюстрациями   программного продукта "Tuebo Delphi", авторское право на который принадлежит "Borland Software Corporation. 


(C) Шуравин Александр 

Последнее обновление ( 12.09.2013 г. )
 
« След.   Пред. »
 
© 2024 Программирование - это просто
Joomla! - свободное программное обеспечение, распространяемое по лицензии GNU/GPL.
Русская локализация © 2005-2008 Joom.Ru - Русский Дом Joomla!
Design by Mamboteam.com | Powered by Mambobanner.de
Я принимаю Яндекс.Деньги