sharptooth
sharptooth

Reputation: 170509

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():
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?

Upvotes: 4

Views: 2195

Answers (2)

vines
vines

Reputation: 5225

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;
}

Upvotes: 1

Rob Kennedy
Rob Kennedy

Reputation: 163317

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.

Upvotes: 2

Related Questions