Программирование COM в Delphi. Урок 4. Использование интерфейсов. |
Автор megabax | ||||||||||||||
27.08.2011 г. | ||||||||||||||
Программирование COM в Delphi. Урок 4. Использование интерфейсов.Исходники к уроку можно скачать здесь Сегодня мы разберем простой пример использования интерфейсов. Пусть перед нами стоит задача разработать библиотеку для конвертации в строку различных типов данных. Начнем программирование этой библиотеки с создания интерфейса:
На основании этого интерфейса объявим классы для конвертации числа в строку в виде обычно числа и в виде шестнадцатеричного кода:
Теперь реализуем класс TFormattedInteger:
и TFFotmattedHexInteger:
А теперь займемся тестированием классов. Создадим вот такую форму*: По кнопочке btnAsObject мы тестируем создание объекта как объекта:
Посмотрим, как это работает: Возникает вопрос, почему у нас выскакивает TFormattedInteger.Destroy после TFotmattedHexInteger.Destroy? Все правильно, TFotmattedHexInteger объявлен как дочерний от TFormattedInteger. Уничтожая объект TFotmattedHexInteger мы вызывает его деструктор, а тот в свою очередь, вызывает деструктор TFormattedInteger. И еще у нас интересный вопрос, почему у нас число преобразуется в десятичный формат, а не в шестнадцатеричный? Ответ на него очень простой. Мы объявили переменную типа TFormattedInteger, а метод FormattedString у нс не виртуальный, поэтому, независимо от того, что присвоили мы объект TFotmattedHexInteger, у нас все равно будет вызываться FormattedString от класса FormattedString. Что бы исправить данную ошибку, достаточно метод FormattedString сделать виртуальным:
После этого мы увидим совершенно другую картину: На самом деле ошибка допущена умышленно, для чистоты эксперимента. Так что проверив, верните код "на место", сделав FormattedString снова не виртуальным. Идем дальше. Попробуем объявить переменную типа IFormattedNumber и присвоить ей объект типа TFotmattedHexInteger (кнопочка btnAsInterfaceClick):
И что же мы видим? Теперь работает правильно: Спрашивается, почему? Да потому, что при присваивании переменной интерфейсного типа какого либо объекта она автоматический принимает тип этого объекта. Это все равно что написать что то в этом роде:
Кстати, заметьте, мы явно не вызываем деструктор объекта TFotmattedHexInteger, но он у нас все равно вызывается. Это связано с особенностью использования интерфейса: когда указатель на интерфейс больше не используется, связанный с ним объект автоматически уничтожается, путем вызова деструктора онного. Аналогично будет уничтожаться объект, если интерфейсной переменной присвоить null:
Давайте запустим эту программу и убедимся в этом: Для следующих тестов нам понадобиться написать две функции, которые вставим как методы в главную форму программы:
Теперь напишем программу, которая покажет имя создаваемых объектов:
и протестируем ее: Если мы раскомментируем строчку:
то произойдет исключительна ситуация (программа выдаст страшное сообщение)*: потому что к интерфейсу нельзя непосредственно применять деструктор - он вызывается автоматический. Может возникнуть вопрос, а с какой радости MyInt - интерфейс, когда эта переменная объявлена как TFormattedInteger? Все дело в том, что она передается в качестве параметра в функцию, у которой аргумент - интерфейс (IFormattedNumber). При такой передаче переменная приобретает свойство интерфейса. Об этой особенности следует помнить, если у вас есть процедуры или функции, которые в качестве аргумента используют интерфейсы. Но если аргумент объявлен как const, (см. функцию ShowNameConst), то данный эффект не будет наблюдаться:
Давайте проверим: Исходники к уроку можно скачать здесь.. Скриншоты, помеченные знаком * , являются цитатами и иллюстрациями программного продукта "Tuebo Delphi", авторское право на который принадлежит "Borland Software Corporation. (C) Шуравин Александр |
||||||||||||||
Последнее обновление ( 12.09.2013 г. ) |
« След. | Пред. » |
---|