Сущность технологии СОМ. Библиотека программиста
Шрифт:
STDMETHODIMP CarPlane::QueryInterface(REFIID riid, void **ppv)
{
if (riid == IID_IUnknown) *ppv = static_cast<IUnknown*>(&m_xCar);
else if (riid == IID_IVehicle) *ppv = static_cast<IVehicle*> (&m_xCar);
else if (riid == IID_ICar) *ppv = static_cast<ICar*>(&m_xCar);
else if (riid == IID_IPlane) *ppv = static_cast<IPlane*>(&m_xPlane);
else return (*ppv = 0), E_NOINTERFACE;
((IUnknown*)(*ppv))->AddRef;
return S_OK;
}
Для обеспечения идентификации объекта каждый из элементов данных CarPlane должен или воспроизвести
inline CarPlane CarPlane::XCar::This(void)
{
return (CarPlane*)((char*)this
// ptr to composite – указатель на композит – offsetof (CarPlane, m_xCar)); }
inline CarPlane CarPlane::XPlane::This(void)
{
return (CarPlane*)((char*)this
// ptr to composite – указатель на композит
– offsetof(CarPlane, m_xPlane));
}
Такая технология вычисления обратного указателя (back-pointer) компактна и чрезвычайно эффективна, так как не требует явных элементов данных для нахождения главного объекта внутри реализации метода элемента данных. При наличии таких алгоритмов вычисления обратного указателя реализация композитного QueryInterface становится тривиальной:
STDMETHODIMP CarPlane::XCar::QueryInterface(REFIID r, void**p)
{
return This->QueryInterface(r, p);
}
STDMETHODIMP CarPlane::XPlane::QueryInterface(REFIID r, void**p)
{
return This->QueryInterface(r, p);
}
Такая же передача this потребуется для AddRef и Release для получения обобщенного представления о времени жизни объекта в случае составных (композитных) элементов данных.
Технология, основанная на использовании композиции для реализации интерфейсов, требует значительно больше кода, чем при простом множественном наследовании. Кроме того, качество генерированного кода, вероятно, не лучше (а возможно, и хуже), чем в случае множественного наследования. Из того факта, что классу CarPlane не понадобилось наследовать ни одному интерфейсу СОМ, следует, что композиция является разумной технологией для внесения СОМ в старые библиотеки классов. Например, MFC (Microsoft Foundation Classes – библиотека базовых классов Microsoft) использует эту технологию. Причиной применения композиции при реализации новых классов является получение отдельных реализации метода, определенного одинаково более чем в одном интерфейсе. К счастью, стандартные интерфейсы, определяемые СОМ, очень редко создают такие конфликты, а те немногие, которые создают, почти всегда преобразуются в семантически эквивалентные функции. Для разрешения коллизий, подобных тем, что произошли в сценарии с GetMaxSpeed , композиция, вероятно, и не требуется, так как в первом приближении для преобразования двойников в уникальные объекты достаточно использования промежуточных классов.
Иногда желательно разместить ресурсы в объекте на базе уже использующихся интерфейсов. В то же время из использования множественного наследования для реализации интерфейсов СОМ следует, что в каждой таблице vtbl будет использована только одна реализация AddRef и Release. Хотя можно выявить первый запрос на заданный интерфейс и разместить ресурсы по требованию:
STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
{
if (riid == IID_IBoat)
{
// allocate resource the first time through
// размещаем ресурсы при первом проходе
if (m_pTonsOfMemory == 0) m_pTonsOfMemory = new char[4096 * 4096];
*ppv = static_cast<IBoat*>(this);
}
else if
…
}
не существует способа определить момент, когда больше нет внешних указателей интерфейса IBoat, так как вызов Release, который клиент делает через интерфейс IBoat, неотличим от вызова Release, сделанного через любой другой интерфейс объекта. В обычной ситуации именно это и нужно, но в данном случае вызовы AddRef и Release через интерфейсы IBoat необходимо рассматривать иначе. Если бы интерфейс IBoat был реализован с использованием композиции, то он имел бы свои собственные уникальные реализации AddRef и Release, в которых он мог бы поддерживать свой собственный счетчик ссылок, отличный от счетчика главного объекта:
class CarBoatPlane : public ICar, public IPlane
{
LONG m_cRef;
char *m_pTonsOfMemory;
CarBoatPlane (void) : m_cRef(0),
m_pTonsOfMemory (0) {}
public:
// IUnknown methods – методы IUnknown
STDMETHODIMP QueryInterface(REFIID, void**);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// IVehicle methods – методы IVehicle
STDMETHODIMP GetMaxSpeed(long *pMax);
// ICar methods – методы ICar
STDMETHODIMP Brake(void);
// IPlane methods – методы IPlane
STDMETHODIMP TakeOff(void);
// define nested class that implements IBoat
// определяем вложенный класс, реализующий IBoat
struct XBoat : public IBoat {
// get back pointer to main object
// получаем обратный указатель на главный объект
inline CarBoatPlane* This;
LONG m_cBoatRef;
// per-interface ref count
// счетчик ссылок на каждый интерфейс
XBoat(void) : m_cBoatRef(0) {}
STDMETHODIMP QueryInterface(REFIID, void**);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
STDMETHODIMP GetMaxSpeed(long *pval);
STDMETHODIMP Sink(void);
};
XBoat m_xBoat; };
Реализация AddRef и Release из IBoat могут теперь следить за числом ссылок типа IBoat и высвободить ресурсы, когда они больше не нужны:
STDMETHODIMP_(ULONG) CarBoatPlane::XBoat::AddRef
Истинная со скидкой для дракона
Любовные романы:
любовно-фантастические романы
рейтинг книги
Герцог и я
1. Бриджертоны
Любовные романы:
исторические любовные романы
рейтинг книги
На границе империй. Том 9. Часть 5
18. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
рейтинг книги
Росток
2. Хозяин дубравы
Фантастика:
попаданцы
альтернативная история
фэнтези
рейтинг книги
Демон
2. История одного эволюционера
Фантастика:
рпг
постапокалипсис
рейтинг книги
Огромный. Злой. Зеленый
1. Большой. Зеленый... ОРК
Любовные романы:
любовно-фантастические романы
рейтинг книги
Запечатанный во тьме. Том 1. Тысячи лет кача
1. Хроники Арнея
Фантастика:
уся
эпическая фантастика
фэнтези
рейтинг книги
Тайны ордена
6. Девятый
Фантастика:
боевая фантастика
попаданцы
рейтинг книги
Кодекс Охотника. Книга VI
6. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
рейтинг книги
Неудержимый. Книга XXI
21. Неудержимый
Фантастика:
попаданцы
аниме
фэнтези
рейтинг книги
Возлюби болезнь свою
Научно-образовательная:
психология
рейтинг книги
