Also this means changes to the underlying representation don’t always require changes to the dependent classes, which I suppose you could consider an ABI change.
Maybe an easier way to characterize it is to consider the virtual classes a way to implement plug ins.
Many people consider virtual inheritance a complexity of the language. Why is it possible for a class to inherit from a base class multiple times through multiple paths (the standard case) or to have the compiler coalesce those paths so that the child class only inherits once from the parent/grandparent? The thing is, once you have multiple inheritance, somebody is going to try to inherit from the same base class multiple times. The language can either support it or declare it an error. It’s not clear to me why it’s wrong to for the language to allow it, even though everywhere I’ve worked with a C++ coding standard has said “if your design requires virtual inheritance, discuss your design with other experienced programmers to see if that can be changed.”
It's a no-win choice, though I agree C++ chose the wrong path: trying as much as possible to avoid adding new keywords. It leads to the problem you describe, as well as some confusion in this very thread (which could be my fault, but honestly I don't know -- that's the problem!).
The committee seems to have moved away from this over the years which has lead to complaints of too many keywords and identifiers. Which is why I call it no win.
The function virtual specifier in the base clause is reasonable: if you store something into parent_class.instannce_var and there are two copies of parent_class in your structure which one is stored to and is the choice consistent in all compilation units? This specifier guarantees that the answer is "yes". I don't know why it isn't the default though.
More generally, back in the day I used to use a bunch of different method combinators with flavors (later CLOS). Apart from the useful :before and :after, they generally lead to undebuggable code.
I do think it's a useful feature, except as I think most people finally agree, MI is more often than not a cause for confusion.
It's funny that of all the different method combinators (another source of confusion) only that one was chosen.
BTW I don't think a unique_ptr is needed in the case I described.