Компоненты: Повторное применение; Использование.
Наследование в С++ и СОМ
Парадигмы ООП Инкапсуляция Наследование Полиморфизм
Наследование в С++ С++ - наследование реализации Class A { void foo(void) { … } Class B:public A { }
Наследование в СОМ СОМ – наследование интерфейса. Interface IX { HRESULT Foo1([in] int param); } Interface IX2: interface IX { HRESULT Foo2([in] long P1, [in] long P2); }
Включение и агрегирование IFly IRotor ILeherRotor ICryoZotRotor
Включение и агрегирование IRotor ILeherRotor ICryoZotRotor IRotor Внешний компонент Внутренний компонент Внешний компонент Внутренний компонент
Включение
Агрегирование
Сравнение включения и агрегирования - код поддержки включение: есть немного агрегирование: есть особый - свой дополнительный код включение: есть агрегирование: нет - расширение функциональности включение: за счет своего кода агрегирование: за счет готовых компонентов
Реализация включения class CA : public IX, public IY { public: // IUnknown virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv); virtual ULONG __stdcall AddRef(); virtual ULONG __stdcall Release(); // Интерфейс IX virtual void __stdcall Fx() { cout
Реализация включения // // Конструктор // CA::CA() : m_cRef(1), m_pIY(NULL) { ::InterlockedIncrement(&g_cComponents); } // // Деструктор // CA::~CA() { ::InterlockedDecrement(&g_cComponents); trace("Самоликвидация"); // Освободить включаемый компонент if (m_pIY != NULL) { m_pIY->Release(); }
Реализация включения // Инициализация компонента путем создания включаемого компонента HRESULT __stdcall CA::Init() { trace("Создать включаемый компонент"); HRESULT hr = ::CoCreateInstance(CLSID_Component2, NULL, CLSCTX_INPROC_SERVER, IID_IY, (void**)&m_pIY); if (FAILED(hr)) { trace("Не могу создать включаемый компонент"); return E_FAIL; } else { return S_OK; }
Реализация включения HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv) { // Агрегирование не поддерживается if (pUnknownOuter != NULL) return CLASS_E_NOAGGREGATION; // Создать компонент CA* pA = new CA; if (pA == NULL) return E_OUTOFMEMORY; // Инициализировать компонент HRESULT hr = pA->Init(); if (FAILED(hr)) { // Ошибка при инициализации. Удалить компонент pA->Release(); return hr; } // Получить запрошенный интерфейс hr = pA->QueryInterface(iid, ppv); pA->Release(); return hr; }
Использование включения interface IAirplane : IUnknown { void TakeOff(); void Fly(); void Land(); }; interface IFloatPlane : IAirplane { void LandingSurface(UINT iSurfaceType); void Float(); void Sink(); void Rust(); void DrainBankAccount(); };
Использование включения void CmyFloatPlane::Fly() { m_pIAirplane->Fly(); } void CmyFloatPlane::Land() { if (m_iLandingSurface == WATER) { WaterLanding(); } else { m_pIAirplane->Land(); }
Реализация агрегирования QueryInterface IX IY QueryInterface?
Реализация агрегирования class CA : public IX { public: // IUnknown virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv); virtual ULONG __stdcall AddRef(); virtual ULONG __stdcall Release(); // Интерфейс IX virtual void __stdcall Fx() { cout
Реализация агрегирования HRESULT __stdcall CA::QueryInterface(const IID& iid, void** ppv) { if (iid == IID_IUnknown) { *ppv = static_cast (this); } else if (iid = IID_IX) { *ppv = static_cast (this); } else if (iid = IID_IY) { return m_pUnknownInner->QueryInterface(iid, ppv); } else { *ppv = NULL; return E_NOINTERFACE; } reinterpret_cast (*ppv)->AddRef(); return S_OK; }
Реализация агрегирования
HRESULT __stdcall CoCreateInstance( const CLSID& clsid, IUnknown* pUnknownOuter, // Внешний компонент DWORD dwClsContext, // Контекст сервера const IID& iid, void** ppv ); HRESULT __stdcall CreateInstance( IUnknown* pUnknownOuter, const IID& iid, void** ppv );
Реализация агрегирования
struct InondelegatingUnknown { virtual HRESULT __stdcall NondelegatingQueryInterface(const IID&, void**) = 0; virtual ULONG __stdcall NondelegatingAddRef() = 0; virtual ULONG __stdcall NondelegatingRelease() = 0; };
Реализация агрегирования HRESULT __stdcall CB::NondelegatingQueryInterface(const IID& iid, void** ppv) { if (iid == IID_IUnknown) { *ppv = static_cast (this); } else if (iid = IID_IY) { *ppv = static_cast (this); } else { *ppv = NULL; return E_NOINTERFACE; } reinterpret_cast (*ppv)->AddRef(); return S_OK; }
Реализация делегирующего IUnknown class CB : public IY, INondelegatingUnknown { public: // Делегирующий IUnknown virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) { return m_pUnknownOuter->QueryInterface(iid, ppv); } virtual ULONG __stdcall AddRef() { return m_pUnknownOuter->AddRef(); } virtual ULONG __stdcall Release() { return m_pUnknownOuter->Release(); } // Неделегирующий IUnknown virtual HRESULT __stdcall NondelegatingQueryInterface(const IID& iid, void** ppv); virtual ULONG __stdcall NondelegatingAddRef(); virtual ULONG __stdcall NondelegatingRelease(); // Интерфейс IY virtual void Fy() { cout
Создание внутреннего компонента HRESULT CA::Init() { IUnknown* pUnknownOuter = this; HRESULT hr = CoCreateInstance(CLSID_Component2, pUnknownOuter, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&m_pUnknownOuter); if (FAILED(hr)) { return E_FAIL; } return S_OK; }
Создание внутреннего компонента HRESULT __stdcall Cfactory::CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv) { // При агрегировании iid должен быть IID_IUnknown – нужен ТОЛЬКО неделегирующий IUnknown if ((pUnknownOuter != NULL) && (iid != IID_IUnknown)) { return CLASS_E_NOAGGREGATION; } // Создать компонент CB* pB = new CB(pUnknownOuter); if (pB == NULL) { return E_OUTOFMEMORY; } // Получить запрошенный интерфейс HRESULT hr = pB->NondelegatingQueryInterface(iid, ppv); PB->NondelegatingRelease(); return hr; }
Создание внутреннего компонента CB::CB(IUnknown* pUnknownOuter) : m_cRef(1) { ::InterlockedIncrement)&g_cComponents; if (pUnknownOuter == NULL) { // Не агрегируется: использовать неделегирующий IUnknown m_pUnknownOuter = reinterpret_cast ( static_cast (this) ); } else { // Агрегируется: использовать внешний IUnknown m_pUnknownOuter = pUnknownOuter; }
Применение: настройка состояния
Применение: обратный вызов