5.6 Рекомендации по программированию
Наследование классов предоставляет программисту богатейшие возможности организации кода и его многократного использования. Выбор наиболее подходящих средств для целей конкретного проекта основывается на знании механизма их работы и взаимодействия.
Наследование класса Yот классаXозначает, чтоYпредставляет собой разновидность классаX, то есть более конкретную, частную концепцию. Базовый классXявляется более общим понятием, чемY. Везде, где можно использоватьX, можно использовать иY, но не наоборот (вспомните, что на место базового класса можно передавать любой из производных). Необходимо помнить, что во время выполнения программы не существует иерархии классов и передачи сообщений объектам базового класса из производныхесть только конкретные объекты классов, поля которых формируются на основе иерархии на этапе компиляции.
Главное преимущество наследования состоит в том, что на уровне базового класса можно написать универсальный код, с помощью которого работать также с объектами производного класса, что реализуется с помощью виртуальных методов.
Как виртуальные должны быть описаны методы, которые выполняют во всех классах иерархии одну и ту же функцию, но, возможно, разными способами. Пусть, например, все объекты иерархии должны уметь выводить информацию о себе. Поскольку эта информация хранится в различных полях производных классов, функцию вывода нельзя реализовать в базовом классе. Естественно назвать ее во всех классах одинаково и объявить как виртуальную с тем, чтобы ее можно было вызывать в зависимости от фактического типа объекта, с которым работают через базовый класс.
Для представления общих понятий, которые предполагается конкретизировать в производных классах, используют абстрактные классы. Как правило, в абстрактном классе задается набор методов, то есть интерфейс, который каждый из потомков будет реализовывать по-своему.
Обычные (не виртуальные) методы переопределять в производных классах не рекомендуется, поскольку производные классы должны наследовать свойства базовых, а спецификатор new, с помощью которого переопределяется обычный метод, «разрывает» отношение наследования на уровне метода Иными словами, невиртуальный метод должен быть инвариантен относительно специализации, то есть должен сохранять свойства, унаследованные из базового класса независимо от того, как конкретизируется (специализируется) производный класс. Специализация производного класса достигается добавлением новых методов и цереопределением существующих виртуальных методов.
Альтернативным наследованию механизмом использования одним классом другого является вложение, когда один класс является полем другого. Вложение представляет отношения классов «YсодержитX» или «Yреализуется посредствомX».
Для выбора между наследованием и вложением служит ответ на вопрос о том, может ли у Yбыть несколько объектов классаX(«YсодержитX»). Кроме того, вложение используется вместо наследования тогда, когда про классыXиYнельзя сказать, чтоYявляется разновидностьюX, но при этомYиспользует часть функциональностиX(«Y реализуется посредствомX»).