” 1. Почему возникает ошибка?
Учти это:
struct Animal {};
struct Dog: Animal { void bark() {} };
struct Dolphin: Animal { void dive() {} };
void foo( Animal*& p ) { p = new Dolphin(); }
auto main() -> int
{
Dog* p = new Dog();
foo( p ); //! C2664, Would have changed p to point to Dolphin.
p->bark(); // Uh huh...
}
Итак, это не разрешено.
Есть еще одно и то же, например. относительно глубокой const
-ности фактического и формального аргумента, и он широко известен как принцип подстановки Лисков, LSP, в честь Барбары Лисков.
” 2. Как правильно написать?
Одним из решений общей проблемы, как уже упоминал Ханс Пассант, является использование шаблонов для прямой работы с типом или типы под рукой, без преобразования.
Однако в этом конкретном случае, если вы уверены, что у вас нет нулевого указателя, просто вызовите p->Release()
вместо SafeRelease( p )
.
” 3. Если для написания этой функции нельзя использовать наследование, должен ли я использовать шаблоны?
Вы можете использовать шаблоны, но это не обязательно; см. выше.
» 4. Есть ли что-то, с чем мне нужно быть осторожным при реализации этого с использованием предложенного метода?
Предлагаемый метод включает предполагаемое неявное преобразование Derived*
→ Base*
для указателей интерфейса COM.
Обратите внимание, что хотя преобразование Derived*
→ Base*
обычно хорошо работает и с COM-интерфейсами, интерфейс IUnknown
подчиняется очень особым правилам.
А именно, внутри COM-объекта может быть несколько IUnknown
подобъектов, соответствующих возможным IUnknown*
указателям на этот объект, но только одно из этих значений указателя идентифицирует объект.
Поэтому, если вам нужен указатель IUnknown
, который идентифицирует объект, указатель, который можно сравнить с другими указателями IUnknown
, чтобы проверить, является ли это одним и тем же объектом, вы должны использовать QueryInterface
для получения указателя IUnknown
.
К счастью, вы можете использовать QueryInterface
с помощью любого имеющегося у вас указателя интерфейса, а поскольку эта функция-член предоставляется через интерфейс IUnknown
, который наследуют все остальные интерфейсы, это показывает, что вы можете использовать неидентифицирующие указатели IUnknown
для других целей, кроме идентификации.
person
Cheers and hth. - Alf
schedule
14.06.2014
SafeRelease
в статье, в конечном итоге это предполагает, что вы просто не делаете этого вообще, если вы пишете код на C ++ (а вы это делаете). К моменту завершения встраивания я был бы удивлен, если бы шаблонSafeRelease
имел какое-либо преимущество над интеллектуальными указателями, не нарушая фундаментальные правила COM. - person WhozCraig   schedule 14.06.2014