Is there any reason against directly calling AddRef() inside QueryInterface() implementation?
When implementing IUnknown::QueryInterface()
in C++ there're several caveats with pointers manipulation. For example, when the class implements several interfaces (multiple inheritance) explicit upcasts are necessary:
class CMyClass : public IInterface1, public IInterface2 {
};
//inside CMyClass::QueryInterface()开发者_StackOverflow社区:
if( iid == __uuidof( IUnknown ) ) {
*ppv = static_cast<IInterface1*>( this ); // upcast in order to properly adjust the pointer
//call Addref(), return S_OK
}
The reason for upcast is quite clear in multiple inheritance scenarios. However every here and there I also see the following:
static_cast<IUnknown*>( *ppv )->AddRef();
instead of simply invoking AddRef()
from inside QueryInterface()
implementation.
Is there any reason I should do the cast of the value previously copied into ppv
instead of just calling AddRef()
on the current object?
AddRef
is pure virtual in IUnknown
, and none of the other interfaces implement it, so the only implementation in your program is the one you write in CMyClass
. That one method overrides both IInterface1::AddRef
and IInterface2::AddRef
. IUnknown
doesn't have any data members (such as a reference count), so the diamond problem doesn't cause your class to be susceptible to a problem such as different calls to AddRef
acting on different data in the same class.
Calls to this->AddRef()
are going to be routed to the same place as static_cast<IUnknown*>(*ppv)->AddRef()
. I see no reason for the more verbose style.
The reason for the verbose syntax probably lies in the fact that not only this
might be returned in ppv
, which is easy to overlook in a longer if-else-if
. An example from Don Box's Essential COM:
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;
}
精彩评论