Сущность технологии СОМ. Библиотека программиста | страница 61
#include «smartif.h»
void TryToSnoreAndIgnore(/* [in] */ IUnknown *pUnk)
{
// copy constructor calls QueryInterface
// конструктор копирования вызывает QueryInterface
SmartInterface
if (pPug)
// typecast operator returns null-ness
// оператор приведения типа возвращает нуль pPug->Snore();
// operator-> returns safe raw ptr
// оператор -> возвращает прямой указатель
// copy constructor calls QueryInterface
// конструктор копирования вызывает QueryInterface
SmartInterface
if (pCat)
// typecast operator returns null-ness
// оператор приведения типа возвращает нуль pCat->IgnoreMaster();
// operator-> returns safe raw ptr
// оператор -> возвращает прямой указатель
// destructors release held pointers on leaving scope
// деструкторы освобождают удерживаемые указатели при
// выходе из области действия
}
Интеллектуальные указатели выглядят очень привлекательными на первый взгляд, но могут оказаться очень опасными, так как погружают программиста в дремотное состояние; будто бы ничего страшного, относящегося к СОМ, произойти не может. Интеллектуальные указатели действительно решают реальные проблемы, особенно связанные с исключениями; однако при неосторожном употреблении они могут внести столько же дефектов, сколько они предотвращают. Например, многие интеллектуальные указатели позволяют вызывать любой метод интерфейса через оператор интеллектуального указателя –>. К сожалению, это позволяет клиенту вызывать Release с помощью этого оператора-стрелки без сообщения базовому интеллектуальному указателю о том, что его автоматический вызов Release в его деструкторе теперь является излишним и недопустимым.
Оптимизация QueryInterface
Фактически реализация QueryInterface, показанная ранее в этой главе, очень проста и легко может поддерживаться любым программистом, имеющим хоть некоторое представление о СОМ и C++. Тем не менее, многие среды и каркасы приложений поддерживают реализацию, управляемую данными. Это помогает достичь большей расширяемости и эффективности благодаря уменьшению размера кода. Такие реализации предполагают, что каждый совместимый с СОМ класс предусматривает таблицу, которая отображает каждый поддерживаемый IID на какой-нибудь аспект объекта, используя фиксированные смещения или какие-то другие способы. В сущности, реализация QueryInterface , приведенная ранее в этой главе, строит таблицу, основанную на скомпилированном машинном коде для каждого из последовательных операторов if, а фиксированные смещения вычисляются с использованием оператора staticcast (staticcast просто добавляет смещение базового класса, чтобы найти совместимый с типом указатель vptr).