Есть ли случай, когда dynamic_cast должен использоваться в реализации QueryInterface? - PullRequest
2 голосов
/ 03 февраля 2011

Типичный способ реализации IUnknown::QueryInterface() заключается в следующем: используйте цепочку if-else-if для каждого поддерживаемого идентификатора интерфейса и выполните следующее:

if( iid == __uuidof( IInterfaceN ) ) {
   *ppv = static_cast<IInterfaceN>( this );
   //call Addref(), return S_OK
} 

Теперь static_cast необходимо здесь для правильной настройки указателя в сценарии множественного наследования.

Время от времени я вижу реализации, которые вместо этого используют dynamic_cast.IMO - это пустая трата времени - результат будет таким же, просто потребуется больше времени и сделает реализацию более надежной.

Есть ли случаи, когда использование dynamic_cast действительно необходимо для приведения указателя this передскопировать его в void** параметр IUnknown::QueryInterface() реализации?

Ответы [ 2 ]

1 голос
/ 03 февраля 2011

QueryInterface() фактически является реализацией оператора "динамического приведения".Основывать реализацию поверх другой реализации, которая требует другого варианта тех же метаданных (дерева наследования), не имеет никакого реального смысла.

Хороший компилятор должен быть в состоянии преобразовать это в static_cast.

1 голос
/ 03 февраля 2011

Это было бы необходимо в тех реализациях QueryInterface, где "идентификаторы поддерживаемых интерфейсов" неизвестны. Например. если вы решили реализовать QueryInterface в базовом классе, а не переопределять его для каждого производного класса.

Случай, когда это может произойти, - это ситуация, когда у вас есть много схожих типов, где «схожие» означают «реализацию множества одинаковых интерфейсов». То есть у вас есть типы объектов Derived1 ... DerivedN, которые реализуют некоторое подмножество Interface1 ... InterfaceM.

Это может иметь место для игрового движка, где все игровые сущности реализуют подмножество IMoveable, IScriptable, IFactory, IShoots, IPlayerControlled, IStealthy, ISensor и так далее. Конечно, по правилам COM вы должны быть в состоянии вызвать IFactory::QueryInterface и получить IMovable* тогда и только тогда, когда фабрика также реализует IMovable.

Как вы собираетесь реализовать все эти QueryInterface методы? Проще всего вставить базовый класс GameObject между IUnknown и IFactory и реализовать GameObject::QueryInterface с использованием проверок dynamic_cast. Таким образом, вам нужна только одна реализация вместо одной на интерфейс конкретного типа.

...