Вот возможное объяснение:
Когда компилятор связывает вызовы метода, первое место он ищет в классе, который является самым низким в цепочке наследования (в данном случае класс Derived
). Это методы экземпляра проверены и сопоставлены. Переопределенный метод Foo не является методом экземпляра Derived
, это метод экземпляра класса Base
.
Причиной может быть производительность, как предлагал Jack30lena, но также и то, как компилятор интерпретирует намерение кодера. Это безопасное предположение, что предполагаемое поведение кода разработчика лежит в коде в нижней части цепочки наследования.