I think it's not so much the problem of an ABI but the fact that changing base classes in C++ forces client code to be recompiled because offsets of members and vtable entries change:
Apparently Apple gets around this the usual way by padding out their API classes with extra unused members. I wonder what the solution is in Windows 8 & Symbian.
WinRT gets around it because it doesn't really export C++ the way you're thinking. What it exports are basically COM objects with a bunch of extra CLR-style metadata.
COM avoids the C++ issue because it only allows you to consume interfaces, and, for all Windows compilers when COM was invented (and obviously since), vtables are always in a set location. So the trick is:
1. Never change existing interfaces
2. Always add new interfaces to the end of the vtables
When you want a COM object, you instantiate it, but you don't work with it directly; you ask for the interface you want to use to talk to the object. As long as the object vendor maintains the old virtual methods, the worst that happens is you ask for the old interface and everything works as normal. This works very well with only a minor speed hit.
I think right after //build, I could tell you how they used CLR metadata to extend the system out to supporting subclassing, but I just honestly don't remember. Similar general idea, though; they still avoid the problem by not actually hitting it.
This is not only about data member access. It also applies to adding methods on the base class that change the behavior of existing methods in already declared subclasses.
Take a cup of coffee and read this famous paper about the issue,
Mac OS X drivers are written in C++.
Symbian is fully written in C++.
The new WinRT API for Windows 8 is C++ based along as the user space driver framework.
There is no reason why Apple could not have defined a standard C++ ABI in BeOS, if that was the reason.
The decision to take NeXT instead of BeOS, surely did not have anything to do with technical merits of the underlying systems.