В базовых классах с высокой стоимостью изменений (библиотеки), лучше делать открытые функции не виртуальными.
Виртуальные функции лучше делать private или protected, если производный класс должен иметь возможность вызывать их базовые версии ( исключение - деструкторы ).
Открытая virtual функция изначально решает две различные задачи: 1. Она определяет интерфейс - Будучи открытой, такая функция является непосредственной частью интерфейса класса, предоставленного внешнему миру.
2. Она определяет детали реализации- Будучи виртуальной, функция предоставляет производному классу возможность заменить базовую реализацию этой функции (если она была) в чём и состоит цель настройки.
Так как цели этих задач, поставленных перед virtual функцией, различны, то они начинают конфликтовать друг с другом, потому что одна функция не может полностью решить одновременно две задачи.
Преимущества разделения открытых функций от виртуальных: 1. Каждый интерфейс может приобрести свой естественный вид - Когда мы разделяем открытый интерфейс от интерфейса настройки, каждый из них может легко приобретать тот вид, который для него наиболее естественен, не пытаясь найти компромисс, который заставит их выглядеть идентично.
Часто они требуют различного количества функций или параметров.
2. Управление базовым классом- Теперь базовый класс находится под полным контролем своего интерфейса и может обеспечить пост - и предусловия интерфейса, причём выполнить всю эту работу в одном повторно используемом месте - не виртуальные функции интерфейса
3. Базовый класс более устойчив к изменениям - Мы можем позже добавить проверку пост- или предусловий, или разделить выполнение работы на большее количество шагов или переделать её, реализовать более подробное разделение интерфейса и реализации с использованием Pimpl и т. п. в базовом классе. Всё это никак не повлияет на код, использующий данный класс или наследующий его.
Исключения: "NVI" не выполним к деструкторам в связи со специальным порядком их выполнения. Если требуется ковариантность в возвращаемом типе, видимая вызывающему коду без использования dynamic_cast, то проще сделать виртуальную функцию открытой.
|