Я думаю, что это сводится к решению о том, относится ли поведение, о котором вы говорите, к иерархии, о которой «Базовая» знает и которая реализует дочерний элемент.
Если вы используете решение обратного вызова, то метод обратного вызова (в зависимости от подписи) не должен быть реализован в дочернем элементе Base. Это может быть уместно, если, например, вы хотите сказать «это событие произошло» «слушателю события», который может находиться в производном классе или в совершенно не связанном классе, который заинтересован в событии.
Если вы используете решение для виртуальных функций, то вы более тесно связываете внедрение классов Derived и Base.
Интересное чтение, которое может дать ответ на ваш вопрос: Обратные вызовы в C ++ , в которых говорится об использовании Функторов. В Wikipedia также есть пример, который использует шаблонный обратный вызов для сортировки. Вы заметите, что реализация для обратного вызова (который является функцией сравнения) не обязательно должна быть в объекте, который выполняет сортировку. Если бы это было реализовано с использованием виртуальных методов, это было бы не так.