Стандарты программирования на С++. 101 правило и рекомендация | страница 61
>super_string
(расточительно) или в) преобразовать ссылки на >string
в ссылки на >super_string
(затруднительно и потенциально некорректно).• Функции-члены >super_string
не должны получить больший доступ к внутреннему устройству класса >string
, чем свободные функции, поскольку класс >string
, вероятно, не имеет защищенных (>protected
) членов (вспомните — этот класс не предназначался для работы в качестве базового).
• Если класс >super_string
скрывает некоторые из функций класса >string
(а переопределение невиртуальных функций в производном классе не является перекрытием — это просто сокрытие), это может вызвать неразбериху в коде, работающем с объектами string, которые создаются автоматическим преобразованием из класса >super_string
.
Словом, лучше добавлять новую функциональность посредством новых свободных (не являющихся членами) функций (см. рекомендацию 44). Чтобы избежать проблем поиска имен, убедитесь, что вы поместили функции в то же пространство имен, что и тип, для расширения функциональности которого они предназначены (см. рекомендацию 57). Некоторые программисты не любят свободные функции из-за их синтаксиса >Fun(str)
вместо >str.Fun()
, но это не более чем вопрос привычки.
Но что если класс >super_string
наследуется из класса >string
для добавления состояний, таких как кодировка или кэшированное значение количества слов? Открытое наследование не рекомендуется и в этом случае, поскольку класс >string
не защищен от срезки (см. рекомендацию 54), и любое копирование >super_string
в >string
молча уберет все старательно хранимые дополнительные состояния.
И наконец, наследование класса с открытым невиртуальным деструктором рискует получить эффект неопределенного поведения при удалении указателя на объект типа >string
, который на самом деле указывает на объект типа >super_string
(см. рекомендацию 50). Это неопределенное поведение может даже оказаться вполне допустимым при использовании вашего компилятора и распределителя памяти, но оно все равно рано или поздно выявится в виде затаившихся ошибок, утечек памяти, разрушенной кучи и кошмаров переноса на другую платформу.
Примеры
Пример 1. Композиция вместо открытого или закрытого наследования. Что делать, если вам нужен тип >lосаlized_string
, который "почти такой же, как и >string
, но с дополнительными данными и функциями и небольшими переделками имеющихся функций-членов >string
", и при этом реализация многих функций остается неизменной? В этом случае реализуйте ее с помощью класса