Навигация
Главная
Поиск
Форум
FAQ's
Ссылки
Карта сайта
Чат программистов

Статьи
-Delphi
-C/C++
-Turbo Pascal
-Assembler
-Java/JS
-PHP
-Perl
-DHTML
-Prolog
-GPSS
-Сайтостроительство
-CMS: PHP Fusion
-Инвестирование

Файлы
-Для программистов
-Компонеты для Delphi
-Исходники на Delphi
-Исходники на C/C++
-Книги по Delphi
-Книги по С/С++
-Книги по JAVA/JS
-Книги по Basic/VB/.NET
-Книги по PHP/MySQL
-Книги по Assembler
-PHP Fusion MOD'ы
-by Kest
Professional Download System
Реклама
Услуги

Автоматическое добавление статей на сайты на Wordpress, Joomla, DLE
Заказать продвижение сайта
Программа для рисования блок-схем
Инженерный калькулятор онлайн
Таблица сложения онлайн
Популярные статьи
OpenGL и Delphi... 65535
Форум на вашем ... 65535
21 ошибка прогр... 65535
HACK F.A.Q 65535
Бип из системно... 65535
Гостевая книга ... 65535
Invision Power ... 65535
Пример работы с... 65535
Содержание сайт... 65535
ТЕХНОЛОГИИ ДОСТ... 65535
Организация зап... 65535
Вызов хранимых ... 65535
Создание отчето... 65535
Имитационное мо... 65535
Программируемая... 65535
Эмулятор микроп... 65535
Подключение Mic... 65535
Создание потоко... 65535
Приложение «Про... 65535
Оператор выбора... 65535
Реклама
Сейчас на сайте
Гостей: 30
На сайте нет зарегистрированных пользователей

Пользователей: 13,361
новичок: uehuat
Новости
Реклама
Выполняем курсовые и лабораторные по разным языкам программирования
Подробнее - курсовые и лабораторные на заказ
Delphi, Turbo Pascal, Assembler, C, C++, C#, Visual Basic, Java, GPSS, Prolog, 3D MAX, Компас 3D
Заказать программу для Windows Mobile, Symbian

Создание последовательности окон и передвижение окон по экрану на Turbo ...
Моделирование интернет магазина (Apache, Php, Html) на GPSS + Блок схема
Моделирование работы обрабатывающего участка цеха в GPSS

Реализация IUnknown



Имея описанные выше образцы клиентского использования, легко видеть, как реализовать методы IUnknown . Примем предложенную выше иерархию типов Dog/Cat . Чтобы определить С++-класс, который реализует интерфейсы IPug и ICat , нужно просто добавить к списку базовых классов самые последние в иерархии наследования версии интерфейсов:
class PugCat : public IPug, public ICat



При использовании наследования компилятор C++ обеспечивает совместимость двоичного представления производного класса с каждым базовым классом. Для класса PugCat это означает, что все объекты PugCat будут содержать указатель vptr , указывающий на таблицу vtbl , совместимую с IPug . Объекты PugCat также будут содержать указатель vptr , указывающий на вторую таблицу vtbl , совместимую с ICat . Рисунок 2.5 показывает, как интерфейсы в качестве базовых классов соотносятся с представлением объектов.
Поскольку все функции-члены в СОМ-определениях интерфейса являются чисто виртуальными, производный класс должен обеспечивать реализацию каждого метода, имеющегося в любом из его интерфейсов. Методы, общие для двух или более интерфейсов (например, QueryInterface , AddRef и т. д.) нужно реализовывать только один раз, так как компилятор и компоновщик инициализируют все таблицы vtbl так, чтобы они указывали на одну реализацию метода. Таков естественный побочный эффект от использования множественного наследования в языке C++.
Следующий код является определением класса, которое создает объекты, поддерживающие интерфейсы IPug и ICat :
class PugCat : public IPug, public ICat
{
LONG mcRef;
protected:
virtual ~PugCat(void);
public: PugCat(void);
// IUnknown methods
// методы IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
STDMETHODIMP(ULONG) AddRef(void);
STDMETHODIMP(ULONG) Release(void);
// IAnimal methods
// методы IAnimal
STDMETHODIMP Eat(void);
// IDog methods
// методы IDog
STDMETHODIMP Bark(void);
// IPug methods
// методы IPug
STDMETHODIMP Snore(void);
// ICat methods
// методы ICat
STDMETHODIMP IgnoreMaster(void);
};



Отметим, что в классе должен быть реализован каждый метод, определенный в любом интерфейсе, от которого он наследует, так же, как и каждый метод, определенный в любых производных (implied) базовых интерфейсах (например, IDog, IAnimal ). Для создания стековых фреймов, совместимых с СОМ, необходимо использовать макросы STDMETHODIMP и STDMETHODIMP. При ориентации на платформы Win32, использующие компилятор Microsoft C++, заголовки SDK определяют эти два макроса следующим образом:
#define STDMETHODIMP HRESULT stdcall
#define STDMETHODIMP(type) type stdcall



Заголовочные файлы SDK также определяют макросы STDMETHOD и STDMETHO D , которые можно использовать при определении интерфейсов без IDL-компилятора. В серийно выпускаемом программировании на СОМ эти два макроса не нужны.
Реализация AddRef и Release чрезвычайно прозрачна. Элемент данных mcRef отслеживает, сколько неосвобожденных интерфейсных указателей удерживают объект. Конструктор класса приводит счетчик ссылок в нулевое состояние:
PugCat::PugCat(void) : mcRef(0)
// initialize reference count to zero
// устанавливаем счетчик ссылок в нуль
{ }  



Реализация AddRef в классе фиксирует путем увеличения счетчика ссылок, что вызывающий объект продублировал указатель интерфейса. Измененное значение счетчика ссылок возвращается для целей диагностики:
STDMETHODIMP(ULONG) AddRef(void)
{ return ++mcRef; }



Реализация Release фиксирует уничтожение указателя интерфейса простым уменьшением счетчика ссылок, а также производит соответствующее действие, когда счетчик ссылок достигает нуля. Для объектов, находящихся в динамически распределяемой области памяти, это означает вызов оператора delete для уничтожения объекта:
STDMETHODIMP(ULONG) Release(void)
{
LONG res = -mcRef;
if (res == 0) delete this;
return res;
}



Для кэширования обновленного счетчика ссылок необходимо использовать временную переменную, так как нельзя обращаться к элементам данных объекта после того, как объект уже уничтожен.
Заметим, что показанные реализации Addref и Release используют собственные операторы инкремента и декремента (увеличения и уменьшения на единицу). Для простой реализации это весьма разумно, так как СОМ не допускает более одного потока для обращения к объекту до тех пор, пока конструктор не обеспечит явный многопоточный доступ (почему и как конструктор сделает это, подробно описано в главе 5). В случае объектов, доступных в многопоточной среде, для автоматического подсчета ссылок следует использовать подпрограммы Win32 InterlockedIncrement/InterlockedDecrement :
STDMETHODIMP(ULONG) AddRef(void)
{
return InterlockedIncrement(&mcRef);
}
STDMETHODIMP(ULONG) Release(void)
{
LONG res = InterlockedDecrement(&mcRef);
if (res == 0) delete this; return res;
}



Этот код несколько менее эффективен, чем версии, использующие собственные операторы C++. Но, вообще говоря, разумнее использовать менее эффективные варианты InterlockedIncrement / InterlockedDecrement , так как известно, что они надежны во всех ситуациях и освобождают разработчика от необходимости сохранять две версии практически одинакового кода.
Показанные выше реализации AddRef и Release предполагают, что объект может размещаться только в динамически распределяемой области памяти (в «куче») с использованием С++-оператора new . В определении класса деструктор сделан защищенной операцией для обеспечения того, чтобы ни один экземпляр класса не был определен никаким другим способом. Однако иногда желательно иметь объекты, не размещенные в «куче». Для этих объектов вызов delete в последнем вызове Release был бы гибельным. Так как единственной причиной для того, чтобы объект в первую очередь поддерживал счетчик ссылок, была необходимость вызова delete this , допустимо оптимизировать счетчик ссылок для объектов, не содержащихся в динамически распределяемой области памяти:
STDMETHODIMP(ULONG) GlobalVar::AddRef(void)
{
return 2;
// any non-zero value is legal
// допустима любая ненулевая величина
}
STDMETHODIMP(ULONG) GlobalVar::Release (void)
{
return 1;
// any non-zero value is legal
// допустима любая ненулевая величина
}



Эта реализация использует тот факт, что результаты AddRef и Release служат только для сведения и не обязаны быть точными.
При наличии реализации AddRef и Release единственным еще не реализованным методом из IUnknown остается QueryInterface . Его реализации должны отслеживать иерархию типов объекта и использовать статические приведения типов для возврата правильного типа указателя для всех поддерживаемых интерфейсов. Для определения класса PugCat , рассмотренного ранее, следующий код является корректной реализацией QueryInterface : STDMETHODIMP
PugCat::QueryInterface(REFIID riid, void **ppv)
{
assert(ppv != 0);
// or return EPOINTER in production
// или возвращаем EPOINTER в реальный продукт
if (riid == IIDIPug) *ppv = staticcast(this);
else if (riid == IIDIDog) *ppv = staticcast(this);
else if (riid == IIDIAnimal)
// cat or pug?
// кот или мопс?
*ppv == staticcast(this);
else if (riid == IIDIUnknown)
// cat or pug?
// кот или мопс?
*ppv = staticcast(this);
else if (riid == IIDICat) *ppv = staticcast(this);
else
{
// unsupported interface
// неподдерживаемый интерфейс
*ppv = 0;
return ENOINTERFACE;
}
// if we reach this point, *ppv is non-null
// and must be AddRef'ed (guideline A2)
// если мы дошли до этого места, то *ppv ненулевой
// и должен быть обработан AddRef'ом ( принцип A2)
reinterpretcast(*ppv)->AddRef();
return SOK;
}



Использование stati ccast более предпочтительно, чем традиционные приведения типа в стиле С:
*ppv = (IPug*)this;



так как вариант stati ccast вызовет ошибку этапа компиляции, если произведенное приведение типа не согласуется с существующим базовым классом.
Заметим, что в показанной здесь реализации QueryInterface при запросе на интерфейс, поддерживающийся более чем одним базовым интерфейсом (например, IUnknown , IAnimal ) приведение типа должно явно выбрать более определенный базовый класс. Например, для класса PugCat такой вполне безобидно выглядящий код не откомпилируется:
if (riid == IIDIUnknown) *ppv = staticcast(this);



Этот код не пройдет компиляцию, поскольку такое приведение типа является неоднозначным и может соответствовать более чем одному базовому классу. Это было показано в случае FastString и IExtensibleObject из предыдущей главы. Вместо этого реализация должна более точно выбрать тип для приведения:
if (riid == IIDIUnknown) ppv = staticcast(this);
или if (riid == IIDIUnknown) ppv = staticcast(this);



Каждый из этих двух фрагментов кода допустим для реализации PugCat . Первый вариант предпочтительнее, так как многие компиляторы выдают несколько более эффективный код, когда использован крайний левый базовый класс [1] .
Опубликовал Kest July 12 2009 21:38:53 · 0 Комментариев · 7326 Прочтений · Для печати

• Не нашли ответ на свой вопрос? Тогда задайте вопрос в комментариях или на форуме! •


Комментарии
Нет комментариев.
Добавить комментарий
Имя:



smiley smiley smiley smiley smiley smiley smiley smiley smiley
Запретить смайлики в комментариях

Введите проверочный код:* =
Рейтинги
Рейтинг доступен только для пользователей.

Пожалуйста, залогиньтесь или зарегистрируйтесь для голосования.

Нет данных для оценки.
Гость
Имя

Пароль



Вы не зарегистрированны?
Нажмите здесь для регистрации.

Забыли пароль?
Запросите новый здесь.
Поделиться ссылкой
Фолловь меня в Твиттере! • Смотрите канал о путешествияхКак приготовить мидии в тайланде?
Загрузки
Новые загрузки
iChat v.7.0 Final...
iComm v.6.1 - выв...
Visual Studio 200...
CodeGear RAD Stud...
Шаблон для новост...

Случайные загрузки
Разработка Web-пр...
WinAmp
Модифицированная ...
IpEditAdress
База Allsubmitter...
Основы программир...
Apollovcl61
Ehlib
Java 2. Наиболее ...
Программирование ...
Ведение справочны...
DiskInfo
Cooltray
Последние загруж...
StartMark
PBEditPack
Работа с матрицами
База предприятий ...
Prolog Interprete...
Усложнённый кальк...

Топ загрузок
Приложение Клие... 100772
Delphi 7 Enterp... 97809
Converter AMR<-... 20259
GPSS World Stud... 17014
Borland C++Buil... 14189
Borland Delphi ... 10267
Turbo Pascal fo... 7372
Калькулятор [Ис... 5972
Visual Studio 2... 5206
Microsoft SQL S... 3661
Случайные статьи
Связывание текстов...
Определяя переменн...
Каждый столбец име...
Особенности разраб...
Исключения и дестр...
присвоения чрезмер...
Организация ввода-...
Исключительные сит...
В здании несколько...
Протокол установле...
Активация и SCM
В перспективе VRML
НЕОДНОЗНАЧНЫЕ ГРУППЫ
убедиться, что сет...
Получи, клиент, ра...
Основные принципы ...
Модификации с бесп...
Особенности постро...
Утилиты: библиотек...
Определить слова, ...
Domain Admins Admi...
Пакет android.net.sip
Сокеты [5]
Краткий обзор пото...
Какая логика подра...
Статистика



Друзья сайта
Программы, игры


Полезно
В какую объединенную сеть входит классовая сеть? Суммирование маршрутов Занимают ли таблицы память маршрутизатора?