Как работает реализация нескольких COM-интерфейсов в C++?

Я пытаюсь понять этот пример кода относительно объектов Browser Helper.

Внутри автор реализует один класс, который предоставляет несколько интерфейсов (IObjectWithSite, IDispatch).

Его функция QueryInterface выполняет следующее:

if(riid == IID_IUnknown) *ppv = static_cast<BHO*>(this);
else if(riid == IID_IObjectWithSite) *ppv = static_cast<IObjectWithSite*>(this);
else if (riid == IID_IDispatch) *ppv = static_cast<IDispatch*>(this);

Я узнал, что с точки зрения C указатели интерфейса - это всего лишь указатели на VTables. Поэтому я понимаю, что C++ способен возвращать VTable любого реализованного интерфейса, используя static_cast.

Означает ли это, что класс, созданный таким образом, имеет в памяти несколько VTables (IObjectWithSite, IDispatch и т. Д.)? Что делает C++ с конфликтами имен на разных интерфейсах (каждый из них имеет функции QueryInterface, AddRef и Release), могу ли я реализовать разные методы для каждого из них?

2 ответа

Решение

Да, существует несколько v-таблиц, по одной для каждого унаследованного интерфейса. Static_cast<> возвращает его. Компилятор обеспечивает совместное использование общих методов в унаследованных интерфейсах, заполняя каждый слот v-таблицы указателем на одну и ту же функцию. Таким образом, вам нужна только одна реализация AddRef, Release, QueryInterface. Как раз то, что вы хотите. Ничто из этого не является случайностью.

Это всегда проблема, когда в Coclass реализовано несколько интерфейсов с одним и тем же методом, который вы не хотите использовать в одной и той же реализации. Метод IConnectionPoint::Advise() является пресловутым примером. Или это был DAdvise()? К сожалению, я не помню, с чем это столкнулось и как это было решено, это было покрыто ATL Internals. Очень хорошая книга, кстати.

При множественном наследовании несколько таблиц VT располагаются в последовательности, подобной следующему формату, если дано this указатель (который указывает на первый байт, 01)

[01] [02] [03] [04] [05] [06] [07] [08] [09] [10] [11] [12]
[Ptr VTableA][Ptr VTableB][Ptr VTableC]

В C++ только одна реализация будет сгенерирована для прототипа функции в сценарии с несколькими интерфейсами. Однако для обычного сценария наследования суперкласс может иметь предопределенную реализацию, и дочерние элементы, которые переопределяют функцию, будут иметь свои VTables, указывающие на содержимое, отличное от родительского.

Другие вопросы по тегам