Как работает реализация нескольких COM-интерфейсов в C ++? - PullRequest
5 голосов
/ 14 июня 2010

Я пытаюсь понять этот пример кода относительно объектов 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 ]

7 голосов
/ 14 июня 2010

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

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

3 голосов
/ 14 июня 2010

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

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

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

...