While it is implementation dependent, it is also fairly predictable. Especially historically speaking, the compilers layout members in declaration order. For fields (instance data) that means each field get assigned the next offset in the object (after alignment is rounded up as required), and, each virtual method that is introduced, is assigned next vtable slot. (Overrides share the same vtable slot as the virtual method that they override in the base class.)
Multiple inheritance complicates field & vtable layouts, introducing a notion of sections that group the field and vtable entries, and, the generated code has to switch between sections as their usage demands.
Because among other things, C is the default standard for foreign function calling, many tools and programs rely on C to layout structs in the predictable order they have always done.
C++ compilers are allowed some latitude for certain constructs these days, but as you have described, to be used with COM (which is of course a Microsoft standard, not a C++ language standard), they have also need to be predictable.