Сущность технологии СОМ. Библиотека программиста

ОглавлениеДобавить в закладки К обложке

Другой способ обеспечения множественных реализации конфликтных методов состоит в том, чтобы усилить правила IUnknown . Спецификация СОМ не требует, чтобы объект был реализован как класс C++. Хотя существует весьма естественное соответствие между объектами СОМ и классами C++, базирующимися на множественном наследовании, это всего лишь одна из возможных технологий реализации. Для создания объекта СОМ может быть использована любая программная технология, производящая таблицы vtbl в нужном формате и удовлетворяющая правилам СОМ для QueryInterface. Один стандартный метод разрешения конфликтов имен состоит в реализации интерфейсов с конфликтующими именами как отдельных классов C++ и последующей компоновке целевого класса C++ из экземпляров этих отдельных классов. Для гарантии того, что каждый из этих составных элементов данных появится во внешнем мире как единый объект СОМ, часто назначается одна главная реализация QueryInterface, которой каждый составной элемент данных будет передавать функции. Следующий код демонстрирует эту технологию:

class CarPlane

{

LONG m_cRef;

CarPlane(void) : m_cRef(0) {}

public:

// Main IUnknown methods

// Главные методы IUnknown

STDMETHODIMP QueryInterface(REFIID, void**);

STDMETHODIMP_(ULONG) AddRef(void);

STDMETHODIMP_(ULONG) Release(void);

private:

// define nested class that implements ICar

// определяем вложенный класс, реализующий

ICar struct XCar : public ICar

{

// get back pointer to main object

// получаем обратный указатель на главный объект

inline CarPlane* This();

STDMETHODIMP QueryInterface(REFIID, void**);

STDMETHODIMP_(ULONG) AddRef(void);

STDMETHODIMP_(ULONG) Release(void);

STDMETHODIMP GetMaxSpeed(long *pval);

STDMETHODIMP Brake(void);

};

// define nested class that implements IPlane

// определяем вложенный класс, реализующий IPlane

struct XPlane : public IPlane {

// Get back pointer to main object

// получаем обратный указатель на главный объект

inline CarPlane* This();

STDMETHODIMP QueryInterface(REFIID, void**);

STDMETHODIMP_(ULONG) AddRef(void);

STDMETHODIMP_(ULONG) Release(void);

STDMETHODIMP GetMaxSpeed(long *pval);

STDMETHODIMP TakeOff(void);

};

// declare instances of nested classes

// объявляем экземпляры вложенных классов

XCar m_xCar;

XPlane m_xPlane;

};

Использование вложенных классов не является обязательным, но оно подчеркивает, что эти подчиненные классы не имеют смысла вне контекста класса CarPlane. Рисунок 4.7 показывает двоичное размещение этого класса и размещения соответствующих vtbl .

Отметим, что имеется два определения вложенного класса, по одному для каждого реализованного им интерфейса. Это позволяет разработчику объекта обеспечить две различных реализации GetMaxSpeed:

STDMETHODIMP CarPlane::XCar::GetMaxSpeed(long *pn) {

// set *pn to max speed for cars

// устанавливаем *pn для максимальной скорости автомобилей

}

STDMETHODIMP CarPlane::XPlane::GetMaxSpeed(long *pn) {

// set *pn to max speed for planes

// устанавливаем *pn для максимальной скорости самолетов

}

Тот факт, что две реализации GetMaxSpeed встречаются в различных определениях вложенных классов, позволяет определить метод дважды и к тому же гарантирует то, что таблицы vtbl, соответствующие ICar и IPlane, будут иметь различные элементы для GetMaxSpeed.

Необходимо также отметить, что хотя класс CarPlane, находящийся на верхнем уровне, реализует методы IUnknown, он не наследует никакому производному от IUnknown классу. Вместо этого объекты CarPlane имеют элементы данных, которые наследуют интерфейсам СОМ. Это значит, что вместо того, чтобы использовать static_cast для вхождения в объект и нахождения определенного указателя vptr, реализация QueryInterface в CarPlane должна возвратить указатель на тот элемент данных, который реализует запрашиваемый интерфейс:


Логин
Пароль
Запомнить меня