2015-01-03 2 views
2

Я нашел образец реализации в QueryInterface() вдоль этих линий:Правильный способ вызова AddRef() внутри QueryInterface() осуществление

// Inside some COM object implementation ... 

virtual HRESULT __stdcall QueryInterface(REFIID riid, void **ppv) 
{ 
    *ppv = /* Find interface ... */ 
    if (*ppv == nullptr) 
     return E_NOINTERFACE; 

    static_cast<IUnknown *>(*ppv)->AddRef(); // ###   
    return S_OK; 
} 

Линия интерес представляет один помеченный // ### комментарий.

Позвоните по телефону AddRef() по телефону IUnknownstatic_cast -поиск действительно необходим? Или это просто бесполезный шаблонный код?
Другими словами, будет ли простой звонок AddRef() (т. Е. this->AddRef()) быть в порядке? Если нет, то почему?

+0

Если интерфейс-> AddRef отображает это-> AddRef, то, полагаю, вы могли бы просто использовать 'this', но так ли это всегда? –

+0

@ 500-InternalServerError: Предположим, что вышеуказанный код является частью некоторой реализации COM-объекта, например 'class CSomeComponent: public IInterface1, public IInterface2 {...};'. Что было бы неправильно с простым 'AddRef();' call, а не 'static_cast (* ppv) -> AddRef();' call? –

+0

BTW: В [этой статье MSDN] (http://msdn.microsoft.com/en-us/magazine/dn879357.aspx) - в соответствии с вышеупомянутым шаблоном вызова AddRef - он читает, что _ "[...] AddRef is вызывается через результирующий указатель интерфейса снова, чтобы поддерживать некоторые редкие, но допустимые сценарии составления классов «_. Интересно, каковы эти сценарии и каковы технические причины этого метода addRef() «call-style» ... –

ответ

2

Уверен, у вас обычно есть только одна реализация AddRef(), поэтому не имеет значения, как вы ее называете. Обратите внимание, как способ, которым код использовал ppv, был возможным вдохновением, он бесчестен (void **), поэтому требуется бросок. Может быть, отрыв заставит вас сделать это по-другому.

0

Возвращенный интерфейс не обязательно должен быть базовым классом класса, реализующего QueryInterface.

+0

Я не понимаю ... Не могли бы вы рассказать подробнее? Благодарю. Почему простой 'AddRef()' вызов был неправильным? –

2

Основными причинами являются отрывные интерфейсные указатели (например, для редко используемых интерфейсов) и агрегируемые объекты (COM-эквивалент mixins, более или менее).

В этих случаях (отрыв или агрегатор при запросе на агрегированный IID) ppv не является указателем интерфейса на тот же объект C++ с подсчетом ссылок. Таким образом, этот код необходим, если вы хотите также поддерживать эти случаи.

Позвонив по телефону this->AddRef, возможно, вы получаете немного простоты или типа безопасности, но за счет отсутствия поддерживающих интерфейсов, явно не реализованных одним и тем же объектом C++.


P.S .: Вопреки тому, что большинство книг и документации, на мой взгляд:

  1. Aggregation больше похоже на использование Примеси, чем на наследование или композицию;
  2. Агрегация на самом деле является особым случаем (кэшированных) отрывных указателей интерфейса в отличие от специального случая композиции.

Вот моя линия мысли:

  1. При наследовании, вы обычно имеете возможность переопределения (виртуальные) методы, что не так с агрегацией из-за прямой метод вызывает; когда вы используете композицию, вам может потребоваться обернуть входящие объекты, чтобы не допустить, чтобы внутренний объект теряет свою идентичность с данным объектом (например, внутренний объект может передать себя некоторому методу входящего объекта), тогда как агрегирование также означает совместное использование имеющих два набора методов IUnknown на агрегируемых объектах, таким образом не имея этой конкретной проблемы вообще;
  2. Отрыв имеет собственное время жизни, тогда как агрегируемый объект делится своей жизнью с внешним объектом. В противном случае либо может создаваться только при необходимости, хотя агрегаторы обычно создают агрегируемые объекты, как только они сами создаются.