Π§ΠΈΡ‚Π°ΠΉΡ‚Π΅ ΠΊΠ½ΠΈΠ³ΠΈ ΠΎΠ½Π»Π°ΠΉΠ½ Π½Π° Bookidrom.ru! БСсплатныС ΠΊΠ½ΠΈΠ³ΠΈ Π² ΠΎΠ΄Π½ΠΎΠΌ ΠΊΠ»ΠΈΠΊΠ΅

Π§ΠΈΡ‚Π°Ρ‚ΡŒ ΠΎΠ½Π»Π°ΠΉΠ½ Β«Π‘ΡƒΡ‰Π½ΠΎΡΡ‚ΡŒ Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΈ БОМ. Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° программиста». Π‘Ρ‚Ρ€Π°Π½ΠΈΡ†Π° 17

Автор Π”ΠΎΠ½Π°Π»ΡŒΠ΄ Бокс

HRESULT QueryInterface([in] REFIID riid, [out] void **ppv);


ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ (riid) являСтся физичСским ΠΈΠΌΠ΅Π½Π΅ΠΌ Π·Π°ΠΏΡ€ΠΎΡˆΠ΅Π½Π½ΠΎΠ³ΠΎ интСрфСйса. Π’Ρ‚ΠΎΡ€ΠΎΠΉ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ (ppv) ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ Π½Π° ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ интСрфСйсного указатСля, которая Π² случаС ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠ³ΠΎ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ Π±ΡƒΠ΄Π΅Ρ‚ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ Π·Π°ΠΏΡ€ΠΎΡˆΠ΅Π½Π½Ρ‹ΠΉ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° интСрфСйс.

Π’ ΠΎΡ‚Π²Π΅Ρ‚ Π½Π° запрос QueryInterface, Ссли ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Π½Π΅ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ Π·Π°ΠΏΡ€ΠΎΡˆΠ΅Π½Π½Ρ‹ΠΉ Ρ‚ΠΈΠΏ интСрфСйса, ΠΎΠ½ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π²ΠΎΠ·Π²Ρ€Π°Ρ‚ΠΈΡ‚ΡŒ E_NOINTERFACE послС установки *ppv Π² Π½ΡƒΠ»Π΅Π²ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅. Если ΠΆΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ Π·Π°ΠΏΡ€ΠΎΡˆΠ΅Π½Π½Ρ‹ΠΉ интСрфСйс, ΠΎΠ½ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΏΠ΅Ρ€Π΅Π·Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ *ppv ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»Π΅ΠΌ Π·Π°ΠΏΡ€ΠΎΡˆΠ΅Π½Π½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‚ΠΈΡ‚ΡŒ HRESULT S_OK. ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ppv являСтся [out]-ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠΌ, рСализация QueryInterface Π΄ΠΎΠ»ΠΆΠ½Π° Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ AddRef для Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΠΎΠ³ΠΎ указатСля ΠΏΠ΅Ρ€Π΅Π΄ Ρ‚Π΅ΠΌ, ΠΊΠ°ΠΊ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Π²Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‰Π΅ΠΌΡƒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρƒ (см. Π² этой Π³Π»Π°Π²Π΅ Π²Ρ‹ΡˆΠ΅ руководящий ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏ А2). Π­Ρ‚ΠΎΡ‚ Π²Ρ‹Π·ΠΎΠ² AddRef Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ согласован с Π²Ρ‹Π·ΠΎΠ²ΠΎΠΌ Release со стороны ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°. Π‘Π»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ ΠΊΠΎΠ΄ ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ динамичСскоС ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ Ρ‚ΠΈΠΏΠ° с использованиСм ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π° C++ dynamic_cast Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ ΠΈΠ΅Ρ€Π°Ρ€Ρ…ΠΈΠΈ Ρ‚ΠΈΠΏΠΎΠ² Dog/Cat, описанного Ρ€Π°Π½Π΅Π΅ Π² Π΄Π°Π½Π½ΠΎΠΉ Π³Π»Π°Π²Π΅:


void TryToSnoreAndIgnore(/* [in] */ IUnknown *pUnk)

{

IPug *pPug = 0;

pPug = dynamic_cast<IPug*> (pUnk);

if (pPug)

// the object is Pug-compatible

// ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ совмСстим с Pug

pPug->Snore();

ICat *pCat = 0;

pCat = dynamic_cast<ICat*>(pUnk);

if (pCat)

// the object is Cat-compatible

// ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ совмСстим с Cat

pCat->IgnoreMaster();

}


Если ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹ΠΉ этой Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, совмСстим ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ с ICat ΠΈ с IDog, Ρ‚ΠΎ задСйствованы ΠΎΠ±Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½Ρ‹Π΅ возмоТности. Если ΠΆΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Π² Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ Π½Π΅ совмСстим с ICat ΠΈΠ»ΠΈ с IDog, Ρ‚ΠΎ данная функция просто ΠΏΡ€ΠΎΠΈΠ³Π½ΠΎΡ€ΠΈΡ€ΡƒΠ΅Ρ‚ ΠΏΡ€ΠΎΠΏΡƒΡ‰Π΅Π½Π½Ρ‹ΠΉ аспСкт ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° (ΠΈΠ»ΠΈ ΠΎΠ±Π° аспСкта сразу). НиТС ΠΏΠΎΠΊΠ°Π·Π°Π½ сСмантичСски эквивалСнтный Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ с использованиСм QueryInterface:


void TryToSnoreAndIgnore(/* [in] */ IUnknown *pUnk)

{

HRESULT hr;

IPug *pPug = 0;

hr = pUnk->QueryInterface(IID_IPug, (void**)&pPug);

if (SUCCEEDED(hr))

{

// the object is Pug-compatible

// ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ совмСстим с Pug

pPug->Snore();

pPug->Release();

// R2

}

ICat *pCat = 0;

hr = pUnk->QueryInterface(IID_ICat, (void**)&pCat);

if (SUCCEEDED(hr))

{

// the object is Cat-compatible

// ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ совмСстим с Cat

pCat->IgnoreMaster();

pCat->Release(); // R2

}

}


Π₯отя ΠΈΠΌΠ΅ΡŽΡ‚ΡΡ ΠΎΡ‡Π΅Π²ΠΈΠ΄Π½Ρ‹Π΅ различия Π² синтаксисС, СдинствСнная сущСствСнная Ρ€Π°Π·Π½ΠΈΡ†Π° ΠΌΠ΅ΠΆΠ΄Ρƒ двумя ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½Ρ‹ΠΌΠΈ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Π°ΠΌΠΈ ΠΊΠΎΠ΄Π° состоит Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚, основанный Π½Π° QueryInterface, подчиняСтся ΠΏΡ€Π°Π²ΠΈΠ»Π°ΠΌ подсчСта ссылок БОМ.

Π•ΡΡ‚ΡŒ нСсколько тонкостСй, связанных с QueryInterface ΠΈ Π΅Π³ΠΎ ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Π»Π΅Π½ΠΈΠ΅ΠΌ. ΠœΠ΅Ρ‚ΠΎΠ΄ QueryInterface ΠΌΠΎΠΆΠ΅Ρ‚ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Ρ‚ΡŒ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π° Ρ‚ΠΎΡ‚ ΠΆΠ΅ самый БОМ-ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, для ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ ΠΎΠ½ Π²Ρ‹Π·Π²Π°Π½. Π“Π»Π°Π²Π° 4 посвящСна объяснСнию ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ нюанса этого ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π°. ПолСзно, ΠΎΠ΄Π½Π°ΠΊΠΎ, ΠΎΡ‚ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ ΡƒΠΆΠ΅ сСйчас, Ρ‡Ρ‚ΠΎ ΠΊΠ»ΠΈΠ΅Π½Ρ‚ Π½Π΅ Π΄ΠΎΠ»ΠΆΠ΅Π½ Ρ‚Ρ€Π°ΠΊΡ‚ΠΎΠ²Π°Ρ‚ΡŒ AddRef ΠΈ Release ΠΊΠ°ΠΊ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ с ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠΌ. ВмСсто этого слСдуСт Ρ€Π°ΡΡΠΌΠ°Ρ‚Ρ€ΠΈΠ²Π°Ρ‚ΡŒ ΠΈΡ… ΠΊΠ°ΠΊ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ с ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»Π΅ΠΌ интСрфСйса. Π­Ρ‚ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ Π½ΠΈΠΆΠ΅ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ ΠΊΠΎΠ΄ ΠΎΡˆΠΈΠ±ΠΎΡ‡Π΅Π½:


void BadCOMCode(/*[in]*/ IUnknown *pUnk)

{

ICat *pCat = 0;

IPug *pPug = 0;

HRESULT hr;

hr = pUnk->QueryInterface(IID_ICat, (void**)&pCat);

if (FAILED(hr)) goto cleanup;

hr = pUnk->QueryInterface(IID_IPug, (void**)&pPug);

if (FAILED(hr)) goto cleanup;

pPug->Bark();

pCat->IgnoreMaster();

cleanup:

if (pCat) pUnk->Release();

// pCat got AddRefed in QI

// pCat ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ» AddRef Π² QI

if (pPug) pUnk->Release();

// pDog got AddRefed in QI

// pDog ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ» AddRef Π² QI

}


НСсмотря Π½Π° Ρ‚ΠΎ Ρ‡Ρ‚ΠΎ всС Ρ‚Ρ€ΠΈ указатСля: pCat, pPug ΠΈ pUnk – ΡƒΠΊΠ°Π·Ρ‹Π²Π°ΡŽΡ‚ Π½Π° Ρ‚ΠΎΡ‚ ΠΆΠ΅ самый ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, ΠΊΠ»ΠΈΠ΅Π½Ρ‚ Π½Π΅ ΠΈΠΌΠ΅Π΅Ρ‚ ΠΏΡ€Π°Π²Π° ΠΊΠΎΠΌΠΏΠ΅Π½ΡΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ AddRef, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ происходит для pCat ΠΈ pPug ΠΏΡ€ΠΈ Π²Ρ‹Π·ΠΎΠ²Π΅ QueryInterface, Π²Ρ‹Π·ΠΎΠ²Π°ΠΌΠΈ Release для pUnk. ΠŸΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ этого ΠΊΠΎΠ΄Π° Ρ‚Π°ΠΊΠΎΠΉ:


cleanup:

if (pCat) pCat->Release();

// use AddRefed ptr

// ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ AddRef

if (pPug) pPug->Release();

// use AddRefed ptr

// ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ AddRef


Π—Π΄Π΅ΡΡŒ Release вызываСтся для Ρ‚ΠΎΠ³ΠΎ ΠΆΠ΅ интСрфСйсного указатСля, для ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ ΠΈ AddRef (Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»ΠΎ нСявно, ΠΊΠΎΠ³Π΄Π° ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π±Ρ‹Π» Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π΅Π½ ΠΈΠ· QueryInterface). Π­Ρ‚ΠΎ Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Π½ΠΈΠ΅ прСдоставляСт Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΡƒ Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΡƒΡŽ Π³ΠΈΠ±ΠΊΠΎΡΡ‚ΡŒ ΠΏΡ€ΠΈ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°. НапримСр, ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΠΌΠΎΠΆΠ΅Ρ‚ Ρ€Π΅ΡˆΠΈΡ‚ΡŒ ΠΏΠΎΠ΄ΡΡ‡ΠΈΡ‚Ρ‹Π²Π°Ρ‚ΡŒ ссылки Π½Π° ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ интСрфСйс, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹ΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ рСсурсы, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ ΠΎΠ΄Π½ΠΈΠΌ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹ΠΌ интСрфСйсом Π½Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚.

Π•Ρ‰Π΅ ΠΎΠ΄Π½Π° Ρ‚ΠΎΠ½ΠΊΠΎΡΡ‚ΡŒ относится ΠΊΠΎ Π²Ρ‚ΠΎΡ€ΠΎΠΌΡƒ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρƒ QueryInterface, ΠΈΠΌΠ΅ΡŽΡ‰Π΅ΠΌΡƒ Ρ‚ΠΈΠΏ void**. Π’Π΅ΡΡŒΠΌΠ° Π·Π°Π±Π°Π²Π½ΠΎ Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ QueryInterface, ΡΠ²Π»ΡΡŽΡ‰ΠΈΠΉΡΡ основой систСмы Ρ‚ΠΈΠΏΠΎΠ² БОМ, ΠΈΠΌΠ΅Π΅Ρ‚ довольно ΡΠΎΠΌΠ½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ Π² смыслС Ρ‚ΠΈΠΏΠ° Π°Π½Π°Π»ΠΎΠ³ Π² C++:


HRESULT _stdcall QueryInterface(REFIID riid, void** ppv);


Как Π±Ρ‹Π»ΠΎ ΠΎΡ‚ΠΌΠ΅Ρ‡Π΅Π½ΠΎ Ρ€Π°Π½Π΅Π΅, ΠΊΠ»ΠΈΠ΅Π½Ρ‚Ρ‹ Π²Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‚ QueryInterface, пСрСдавая ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρƒ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° интСрфСйсный ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π² качСствС Π²Ρ‚ΠΎΡ€ΠΎΠ³ΠΎ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° вмСстС с IID, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ опрСдСляСт Ρ‚ΠΈΠΏ ΠΎΠΆΠΈΠ΄Π°Π΅ΠΌΠΎΠ³ΠΎ интСрфСйсного указатСля:


IPug *pPug = 0; hr = punk->QueryInterface(IID_IPug, (void**)&pPug);


К соТалСнию, для компилятора C++ Ρ‚Π°ΠΊΠΈΠΌ ΠΆΠ΅ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΌ выглядит ΠΈ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π΅:


IPug *pPug = 0; hr = punk->QueryInterface(IID_ICat, (void**)&pPug);


Π”Π°ΠΆΠ΅ Π΅Ρ‰Π΅ Π±ΠΎΠ»Π΅Π΅ Ρ…ΠΈΡ‚Ρ€ΠΎΡƒΠΌΠ½Ρ‹ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ компилируСтся Π±Π΅Π· ошибок:


IPug *pPug = 0; hr = punk->QueryInterface(IID_IPug, (void**)pPug);


Π˜ΡΡ…ΠΎΠ΄Ρ ΠΈΠ· Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ ΠΏΡ€Π°Π²ΠΈΠ»Π° наслСдования Π½Π΅ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΠΌΡ‹ ΠΊ указатСлям, Ρ‚Π°ΠΊΠΎΠ΅ Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π½ΠΎΠ΅ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ QueryInterface Π½e ΠΎΠ±Π»Π΅Π³Ρ‡Π°Π΅Ρ‚ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ:


HRESULT QueryInterface(REFIID riid, IUnknown** ppv);


Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ нСявноС ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ Ρ‚ΠΈΠΏΠ° ΠΊ Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΎΠΌΡƒ Ρ‚ΠΈΠΏΡƒ (upcasting) ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΠΌΠΎ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΊ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°ΠΌ ΠΈ указатСлям Π½Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹, Π° Π½Π΅ ΠΊ указатСлям Π½Π° ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ Π½Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹:


IDerived **ppd; IBase **ppb = ppd;

// illegal

// Π½Π΅Π²Π΅Ρ€Π½ΠΎ


To ΠΆΠ΅ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΠ΅ ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΠΌΠΎ Π² Ρ€Π°Π²Π½ΠΎΠΉ ΠΌΠ΅Ρ€Π΅ ΠΈ ΠΊ ссылкам Π½Π° ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ. Π‘Π»Π΅Π΄ΡƒΡŽΡ‰Π΅Π΅ Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π½ΠΎΠ΅ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ вряд Π»ΠΈ Π±ΠΎΠ»Π΅Π΅ ΡƒΠ΄ΠΎΠ±Π½ΠΎ для использования ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°ΠΌΠΈ:


HRESULT QueryInterface(const IID& riid, void* ppv);


Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ позволяСт ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°ΠΌ ΠΎΡ‚ΠΊΠ°Π·Π°Ρ‚ΡŒΡΡ ΠΎΡ‚ привСдСния Ρ‚ΠΈΠΏΠ° (cast). К соТалСнию, это Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ Π½Π΅ ΡƒΠΌΠ΅Π½ΡŒΡˆΠ°Π΅Ρ‚ количСства ошибок (ΠΎΠ±Π΅ ΠΈΠ· ΠΏΡ€Π΅Π΄ΡˆΠ΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΡ… ошибок всС Π΅Ρ‰Π΅ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹), Π° устраняя Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ привСдСния, ΡƒΠ½ΠΈΡ‡Ρ‚ΠΎΠΆΠ°Π΅Ρ‚ ΠΈ Π²ΠΈΠ΄ΠΈΠΌΡ‹ΠΉ ΠΈΠ½Π΄ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ ΡƒΡΡ‚ΠΎΠΉΡ‡ΠΈΠ²ΠΎΡΡ‚ΡŒ Ρ‚ΠΈΠΏΠΎΠ² C++ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΎΠΊΠ°Π·Π°Ρ‚ΡŒΡΡ Π² опасности. Если ΠΆΠ΅Π»Π°Ρ‚Π΅Π»ΡŒΠ½Π° сСмантика QueryInterface, Ρ‚ΠΎ Π²Ρ‹Π±ΠΎΡ€ Ρ‚ΠΈΠΏΠΎΠ² Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ², сдСланный ΠΊΠΎΡ€ΠΏΠΎΡ€Π°Ρ†ΠΈΠ΅ΠΉ Microsoft, ΠΏΠΎ ΠΊΡ€Π°ΠΉΠ½Π΅ΠΉ ΠΌΠ΅Ρ€Π΅, Ρ€Π°Π·ΡƒΠΌΠ΅Π½, Ссли Π½Π΅ Π½Π°Π΄Π΅ΠΆΠ΅Π½ ΠΈΠ»ΠΈ изящСн. ΠŸΡ€ΠΎΡΡ‚Π΅ΠΉΡˆΠΈΠΉ ΠΏΡƒΡ‚ΡŒ ΠΈΠ·Π±Π΅ΠΆΠ°Ρ‚ΡŒ ошибок, связанных c QueryInterface,– это всСгда Π±Ρ‹Ρ‚ΡŒ ΡƒΠ²Π΅Ρ€Π΅Π½Π½Ρ‹ΠΌ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ IID соотвСтствуСт Ρ‚ΠΈΠΏΡƒ указатСля интСрфСйса, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΡ€ΠΎΡ…ΠΎΠ΄ΠΈΡ‚ ΠΊΠ°ΠΊ Π²Ρ‚ΠΎΡ€ΠΎΠΉ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ QueryInterface. На самом Π΄Π΅Π»Π΅ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ QueryInterface описываСт Β«Ρ„ΠΎΡ€ΠΌΡƒΒ» Ρ‚ΠΈΠΏΠ° указатСля Π²Ρ‚ΠΎΡ€ΠΎΠ³ΠΎ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°. Π˜Ρ… связь ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ усилСна Π½Π° этапС компиляции с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Ρ‚Π°ΠΊΠΎΠ³ΠΎ макроса прСдпроцСссора Π‘:


#define IID_PPV_ARG(Type, Expr) IID_##type,

reinterpret_cast<void**>(static_cast<Type **>(Expr))


Π‘ ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ этого макроса[1] компилятор Π±ΡƒΠ΄Π΅Ρ‚ ΡƒΠ²Π΅Ρ€Π΅Π½ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ Π²Ρ‹Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅, использованноС Π² ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠΌ Π½ΠΈΠΆΠ΅ Π²Ρ‹Π·ΠΎΠ²Π΅ QueryInterface, ΠΈΠΌΠ΅Π΅Ρ‚ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ Ρ‚ΠΈΠΏ ΠΈ Ρ‡Ρ‚ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ изоляции (indirecton):


IPug *pPug = 0; hr = punk->QueryInterface(IID_PPV_ARG(IPug, &pPug));


Π­Ρ‚ΠΎΡ‚ макрос Π·Π°ΠΊΡ€Ρ‹Π²Π°Π΅Ρ‚ Π±Ρ€Π΅ΡˆΡŒ, Π²Ρ‹Π·Π²Π°Π½Π½ΡƒΡŽ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠΌ void**, Π±Π΅Π· ΠΊΠ°ΠΊΠΈΡ…-Π»ΠΈΠ±ΠΎ Π·Π°Ρ‚Ρ€Π°Ρ‚ Π½Π° этапС выполнСния.


РСализация 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