Читаем Стандарты программирования на С++ полностью

Классы, предназначенные для автономного использования, подчиняются правилам проектирования, отличным от правил для базовых классов (см. рекомендацию 32). Использование автономных классов в качестве базовых является серьезной ошибкой проектирования и его следует избегать. Для добавления специфического поведения предпочтительно вместо функций-членов добавлять обычные функции (см. рекомендацию 44). Для того чтобы добавить состояние, вместо наследования следует использовать композицию (см. рекомендацию 34). Избегайте наследования от конкретных базовых классов.

Обсуждение

Использование наследования там, где оно не требуется, подрывает доверие к мощи объектно-ориентированного программирования. В C++ при определении базового класса следует выполнить некоторые специфические действия (см. также рекомендации 32, 50 и 54), которые весьма сильно отличаются (а зачастую просто противоположны) от действий при разработке автономного класса. Наследование от автономного класса открывает ваш код для массы проблем, причем ваш компилятор в состоянии заметить только их малую часть.

Начинающие программисты зачастую выполняют наследование от классов-значений, таких как класс string (стандартный или иной) просто чтобы "добавить больше функциональности". Однако определение свободной функции (не являющейся членом) существенно превосходит создание класса super_string по следующим причинам.

• Свободные функции хорошо вписываются в существующий код, который работает с объектами string. Если же вместо этого вы предоставляете класс super_string, вам придется вносить изменения в ваш код, заменяя типы и сигнатуры функций.

• Функции интерфейса, которые получают параметры типа string, при использовании наследования должны сделать одно из трех: а) отказаться от дополнительной функциональности super_string (бесполезно), б) копировать свои аргументы в объекты 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", и при этом реализация многих функций остается неизменной? В этом случае реализуйте ее с помощью класса string, но не наследованием, а комбинированием (что предупредит срезку и неопределенное полиморфное удаление), и добавьте транзитные функции для того, чтобы сделать видимыми функции класса string, оставшиеся неизменными:

class localized_string {

public:

 // ... Обеспечьте транзитные функции для тех

Перейти на страницу:

Все книги серии C++ In-Depth

Стандарты программирования на С++
Стандарты программирования на С++

Эта книга поможет новичку стать профессионалом, так как в ней представлен сконцентрированный лучший опыт программистов на С++, обобщенный двумя экспертами мирового класса.Начинающий программист найдет в ней простые и понятные рекомендации для ежедневного использования, подкрепленные примерами их конкретного применения на практике.Опытные программисты найдут в ней советы и новые рекомендации, которые можно сразу же принять на вооружение. Программисты-профессионалы могут использовать эту книгу как основу для разработки собственных стандартов кодирования, как для себя лично, так и для группы, которой они руководят.Конечно, книга рассчитана в первую очередь на профессиональных программистов с глубокими знаниями языка, однако она будет полезна любому, кто захочет углубить свои знания в данной области.

Андрей Александреску , Герб Саттер

Программирование, программы, базы данных

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных

Все жанры