Вызовы b статические - во время компиляции компилятор точно знает, какой будет тип b во время выполнения (очевидно, Bar), поэтому он будет напрямую использовать адреса методов, которые будут вызваны.
Виртуальный имеет значение только тогда, когда вы делаете вызов через указатель / ссылку, так как вызов может иметь разные цели во время выполнения. Это будет иметь значение, если, например, вы вызвали function1 для указателя и во время выполнения изменили фактический тип, на который указатель указал.
Теперь ситуация, когда вы вызываете function2 для f, хитрая по двум причинам: функция никогда не переопределяется, и вы используете ссылку, которую нельзя переназначить. Следовательно, действительно умный компилятор, который видит все входные файлы, мог бы сообразить, что цель вызова на самом деле будет иметь 100% достоверность (так как вы не собираетесь добавлять новые классы в уже скомпилированный код). Тем не менее, AFAIK, компиляторы не должны это делать, чтобы вы заплатили за это.
Вообще говоря, если вы не планируете переопределять функцию, не делайте ее виртуальной.