2010-05-11 8 views
4

Lors de l'implémentation IUnknown::QueryInterface() en C++, il existe plusieurs mises en garde avec la manipulation de pointeurs. Par exemple, lorsque la classe implémente plusieurs interfaces (d'héritage multiple) explicit upcasts are necessary:Y a-t-il une raison de ne pas appeler directement AddRef() dans l'implémentation de QueryInterface()?

class CMyClass : public IInterface1, public IInterface2 { 
}; 

//inside CMyClass::QueryInterface(): 
if(iid == __uuidof(IUnknown)) { 
    *ppv = static_cast<IInterface1*>(this); // upcast in order to properly adjust the pointer 
    //call Addref(), return S_OK 
} 

La raison de upcast est tout à fait clair dans plusieurs scénarios d'héritage. Cependant tous ici et là, je vois aussi ce qui suit:

static_cast<IUnknown*>(*ppv)->AddRef(); 

au lieu d'invoquer simplement AddRef() à l'intérieur QueryInterface() mise en œuvre.

Y at-il une raison pour laquelle je devrais faire le moulage de la valeur précédemment copiée dans ppv au lieu de simplement appeler AddRef() sur l'objet courant?

+0

Serait-il possible pour vous d'afficher la définition de la classe IUnknown? – mukeshkumar

+0

@hype: Bien sûr. http://msdn.microsoft.com/en-us/library/ms680509(VS.85).aspx – sharptooth

Répondre

2

AddRef est purement virtuel dans IUnknown, et aucune des autres interfaces ne l'implémente, donc la seule implémentation dans votre programme est celle que vous écrivez en CMyClass. Cette méthode remplace à la foisIInterface1::AddRef et IInterface2::AddRef. IUnknown n'a aucun membre de données (tel qu'un nombre de références), ainsi le problème de diamant ne cause pas votre classe à être sensible à un problème tel que différents appels à AddRef agissant sur différentes données dans la même classe.

Les appels vers this->AddRef() vont être routés au même endroit que static_cast<IUnknown*>(*ppv)->AddRef(). Je ne vois aucune raison pour le style plus bavard.

1

La raison de la syntaxe verbeuse réside probablement dans le fait que non seulement this peut être retourné dans ppv, ce qui est facile à négliger dans un plus long if-else-if. Un exemple de Essential COM Don Box:

STDMETHODIMP Car::IternalQueryInterface(REFIID riid, void **ppv) { 
    if (riid == IID_IUnknown) 
     *ppv = static_cast<IUnknown*>(&m_innerUnknown); 
    else if (riid == IID_IVehicle) 
     *ppv = static_cast<IVehicle*>(this); 
    else if (riid == IID_ICar) 
     *ppv = static_cast<ICar*>(this); 
    else 
     return (*ppv = 0), E_NOINTERFACE; 
    ((IUnknown*)*ppv)->AddRef(); 
    return S_OK; 
}