Как говорит Каспин, ваш первый пример на самом деле не делает ничего полезного. Однако он добавит vpointer, чтобы сообщить производным классам, где найти классы, от которых он унаследован.
Это исправляет любые алмазы, которые вы можете теперь создавать (чего у вас нет), но поскольку структура классов больше не является статической, вы больше не можете использовать static_cast для нее. Я не знаком с задействованным API, но то, что говорит Роб Уокер об IUnkown, может быть связано с этим.
Короче говоря, обычное наследование следует использовать, когда вам нужен ваш собственный базовый класс, который не должен использоваться совместно с классами 'sibling': (a - контейнер, b, c, d - части, у каждого есть контейнер, который объединяет эти части (плохой пример, почему бы не использовать композицию?))
a a a
| | |
b c d <-- b, c and d inherit a normally
\ | /
e
В то время как виртуальное наследование предназначено для случаев, когда ваш базовый класс должен использоваться совместно с ними. (a является транспортным средством, b, c, d являются различными специализациями транспортного средства, e объединяет их)
a
/ | \
b c d <-- b, c and d inherit a virtually
\ | /
d