Earlier quoted context omitted.
Another reasonable choice for some components would be to have a purely C api; everything extern "C", and only PODs (plain old datastructures) in the arguments.
Exactly. Using a pure C interface escapes COM's requirement to register every component (regsvr32) and its overblown "GUID for everything" model, and its baroque way of creating components (somewhat alleviated by various macros and templates, but still). Making an object oriented interface is slightly cumbersome, but you can do it by sending back and forth a cookie (void* or int) of your object as the first parameter…
Or you can combine both: use a pure C interface which returns COM objects. That way, you can keep using COM without having to register anything with regsvr32 or similar.
> I have no idea if this trick will also work on Linux, I don't know how stable GCC / Clang's vtable layout is from version to version
Recent (as in, since around the turn of the millennium) GCC and clang on Linux use a standard vtable layout, defined by the "Itanium ABI" (originally created for Intel's IA-64, but like UEFI and GPT, became a standard across all architectures), so it's also very stable.