Каков порядок указателей метода VTable, если класс реализует более 1 интерфейса? - PullRequest
1 голос
/ 23 марта 2012

Я знаю, что если класс A реализует, например, IUnknown и IComSomething1, то порядок методов VTable будет первым IUnknown, а затем IComSomething1. Насколько я знаю, это всегда порядок, потому что IComSomething1 наследует IUnknown.

Но каков порядок, если класс A реализует IUnknown и IComSomething1 и IComSomething2? Каков порядок указателя метода VTable между IComSomething1 и IComSomething2?

(Вопрос относится не только к COM, но возникает из-за проблемы с COM, которая вызывает функцию по смещению vtable).

Я пытался найти некоторые ответы "там", но не мог найти ни одного прямого, ясного ответа.

Спасибо! : -)

1 Ответ

4 голосов
/ 23 марта 2012

Порядок членов vtable в классе не определен. Действительно, вы можете (и будете!) Находить элементы данных между указателями vtable. Если вы пишете COM, вы должны привести к любому интерфейсу, который вы хотите вернуть в QueryInterface, прежде чем записать его в указатель, в который вы помещаете результат. То есть что-то вроде:

HRESULT QueryInterface(REFIID riid, LPVOID *ppvObject) {
  if (*riid == IID_MY_INTERFACE) {
    *ppvObject = static_cast<IMyInterface *>(this);
    return S_OK;
  } else if (*riid == IID_SOMETHING_ELSE) {
    *ppvObject = static_cast<ISomethingElse *>(this);
    return S_OK;
  } else /* ... */
}

Компилятор позаботится о том, чтобы найти правильное смещение для интерфейса.

Что касается того, как это на самом деле работает, подумайте о том, что это означает - каждый из интерфейсов должен существовать как объект на некотором поддиапазоне смещений внутри объекта. Скажем, у вас есть иерархия классов, которая выглядит следующим образом:

class IA { virtual void foo() = 0; int x;};
class IB { virtual void bar() = 0; int y; };
class C : public IA, public IB { int bar; };

Ваш макет в памяти может выглядеть так:

00000000 vtable ptr for C
00000004 vtable ptr for Ia
00000008 int x
0000000b vtable ptr for Ib
00000010 int y
00000014 int bar

Здесь вы можете получить указатель на Ia, получив смещение 0x00000004 в классе или Ib в 0x0000000b.

В некоторых случаях может быть возможно оптимизировать это далее:

00000000 vtable ptr for C and Ia
00000004 int x
00000008 vtable ptr for Ib
0000000b int y
00000010 int bar

Я не уверен, действительно ли Win32 C ++ ABI делает это. Если вы сделаете это, то таблица C vtable будет начинаться с тех же членов, что и таблица Ia, а затем добавит дополнительные в конце.

...