Есть ли какая-либо причина против прямого вызова AddRef () внутри реализации QueryInterface ()? - PullRequest
4 голосов
/ 11 мая 2010

При реализации IUnknown::QueryInterface() в C ++ есть несколько предостережений с манипулированием указателями. Например, когда класс реализует несколько интерфейсов (множественное наследование), необходимы явные преобразования :

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 
} 

Причиной явного отклика достаточно ясно в сценариях множественного наследования. Однако время от времени я также вижу следующее:

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

вместо простого вызова AddRef() изнутри QueryInterface() реализации.

Есть ли причина, по которой я должен выполнить приведение значения, ранее скопированного в ppv, вместо того, чтобы просто вызывать AddRef() для текущего объекта?

Ответы [ 2 ]

2 голосов
/ 11 мая 2010

AddRef является чисто виртуальным в IUnknown, и ни один из других интерфейсов не реализует его, поэтому единственная реализация в вашей программе - это та, которую вы пишете в CMyClass. Этот один метод переопределяет и IInterface1::AddRef и IInterface2::AddRef. IUnknown не имеет никаких элементов данных (таких как счетчик ссылок), поэтому проблема с алмазом не приводит к тому, что ваш класс восприимчив к такой проблеме, как различные вызовы AddRef, действующие на разные данные в одном классе .

Звонки на this->AddRef() будут направлены в то же место, что и static_cast<IUnknown*>(*ppv)->AddRef(). Я не вижу причин для более многословного стиля.

1 голос
/ 29 января 2018

Причина подробного синтаксиса, вероятно, заключается в том, что не только this может быть возвращено в ppv, что легко пропустить при более длинном if-else-if. Пример из 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;
}
...