Вы всегда должны помнить, что в каждом классе есть 2 части, данные и интерфейс.
Ваш код действительно создал 2 объекта Dog в куче. Что означает, что данные о собаке.
Этот объект имеет размер суммы всех членов данных Dog + Animal + указатель vtable.
Понтеры a и d (lvalues) отличаются с точки зрения интерфейса. Что определяет, как вы можете обращаться с ними по коду. Так что, хотя Animal * a действительно Dog, вы не можете получить доступ к a-> Bark (), даже если существует Dog :: Bark (). d-> Bark () работал бы нормально.
Добавление vtable обратно в изображение, предполагая, что интерфейс Animal имеет Animal :: Move универсальный Move (), и что Dog действительно перезаписывается с помощью Dog :: Move () {как собака}.
Даже если бы у вас был Animal a * и вы выполняли a-> Move () благодаря vtable, вы бы на самом деле Move () {как собака}. Это происходит потому, что Animal :: Move () был (виртуальным) указателем на функцию, перенаправленную на Dog's :: Move () при создании Dog ().