Когда вы пишете (BarInterface*)(foo);
, вы лжете компилятору. Вы говорите, что foo
действительно указатель на BarInterface
, поэтому компилятор вам поверит. Поскольку это не так, вы получаете неопределенное поведение, когда пытаетесь разыменовать указатель. Обсуждать, как ведет себя скомпилированная программа в присутствии неопределенного поведения, часто бессмысленно.
В этом случае способ, которым ваш компилятор заполнил vtables, запись для FooInterface::Foo
, кажется, находится в том же месте, что и запись для BarInterface::Bar
. В результате, когда вы вызываете bar->Bar()
, компилятор просматривает таблицу FooInterface
, находит запись для FooInterface::Foo
и вызывает ее. Если расположение классов будет другим или сигнатуры функций будут другими, это приведет к гораздо более серьезным последствиям.
Разумеется, решение состоит в использовании dynamic_cast
, который может выполнять необходимое боковое приведение.