Containment (KOALAC.CPP)

In containment, the outer object, KoalaC, creates an instance of the inner object, Animal, during KoalaC's initialization process and requests an IAnimal pointer in return. (CKoalaC::Init is called from CreateKoalaContainment, which is called from Reuse's window procedure.) KoalaC will request an IAnimal pointer in the process:


BOOL CKoalaC::Init(void)
{
HRESULT hr;

m_pImpIAnimal=new CImpIAnimal_K(this);

if (NULL==m_pImpIAnimal)
return FALSE;

m_pImpIKoala=new CImpIKoala_C(this);

if (NULL==m_pImpIKoala)
return FALSE;

hr=CreateAnimal(NULL, IID_IAnimal, (void **)&m_pIAnimal);

if (FAILED(hr))
return FALSE;

return TRUE;
}

Inside KoalaC's implementation of the specific IAnimal member functions, KoalaC might choose to use—that is, reuse—the implementations of the same functions in the Animal object by calling them through m_pIAnimal, as any other client would. In this case, KoalaC is delegating all the calls after generating an output message to the debugger:


STDMETHODIMP CImpIAnimal_K::Eat(void)
{
ODS("KoalaC's IAnimal_K::Eat called");
m_pObj->m_pIAnimal->Eat();
return NOERROR;
}

STDMETHODIMP CImpIAnimal_K::Sleep(void)
{
ODS("KoalaC's IAnimal_K::Sleep called");
m_pObj->m_pIAnimal->Sleep();
return NOERROR;
}

STDMETHODIMP CImpIAnimal_K::Procreate(void)
{
ODS("KoalaC's IAnimal_K::Procreate called");
m_pObj->m_pIAnimal->Procreate();
return NOERROR;
}

Animal's implementation of the interface also pumps out similar messages. (The ODS macro and others like it wrap calls to OutputDebugString; you can find these macros in INC\DBGOUT.H.)

When KoalaC is destroyed (from the Reuse client code calling its Release), the destructor calls m_pIAnimal->Release using the RELEASEINTERFACE macro we saw earlier. Animal's interface pointer never actually enters into KoalaC's implementation of QueryInterface because KoalaC has its own implementation. Everything KoalaC does with Animal's interface is exactly what any other client would do with Animal, which is the essence of containment.