I know that if class A implements for example IUnknown and IComSomething1, than the VTable's method order will be first IUnknown and than IComSomething1. As far as I know this is always the order because IComSomething1 inherits IUnknown.
But what is the order if class A implements IUnknown and IComSomething1 and IComSomething2 ? What is the order of the VTable method pointer between IComSomething1 and IComSomething2 ?
(The question does not apply only to COM, but it comes out of a COM issue that it calls the function by a vtable offset).
I tried to find some answers "out there" but I couldn't find any straight, clear, answer.
Thanks! :-)
The order of vtable members in a class is not well-defined. Indeed, you can (and will!) find data members between vtable pointers. If you're writing COM, you should cast to whatever interface you want to return in your QueryInterface
prior to writing it to the pointer you're putting the result in. That is, something like:
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 /* ... */
}
The compiler will take care of finding the right offset for the interface for you.
As for how it actually works, think about what this implies - each of the interfaces must exist as an object at some subrange of offsets within the object.. Say you have a class heirarchy that looks like this:
class IA { virtual void foo() = 0; int x;};
class IB { virtual void bar() = 0; int y; };
class C : public IA, public IB { int bar; };
Your in-memory layout might look like this:
00000000 vtable ptr for C
00000004 vtable ptr for Ia
00000008 int x
0000000b vtable ptr for Ib
00000010 int y
00000014 int bar
Here you can get a pointer to an Ia by getting an offset 0x00000004
into the class, or Ib at 0x0000000b
.
It may in some cases by possible to optimize this further:
00000000 vtable ptr for C and Ia
00000004 int x
00000008 vtable ptr for Ib
0000000b int y
00000010 int bar
I'm not sure if the win32 C++ ABI actually does this. If you do do this, then the C vtable starts with the same members as the Ia vtable, then adds on extra ones at the end.