Чтение онлайн

на главную

Жанры

Стандарты программирования на С++. 101 правило и рекомендация

Александреску Андрей

Шрифт:

• Если класс

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:

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

 // функций-членов string, которые остаются неизменными

 // (например, определите функцию insert, которая

 // вызывает impl_.insert) ...

 void clear; // Маскирует/переопределяет clear

 bool is_in_klingon const; // добавляет функциональность

private:

 std::string impl_;

 // ... дополнительные данные-члены ...

};

Конечно, писать транзитные функции для всех функций-членов, которые вы хотите сохранить, — занятие утомительное, но зато такая реализация существенно лучше и безопаснее, чем использование открытого или закрытого наследования.

Пример 2.

std::unary_function
. Хотя
класс
std::unary_function
не имеет виртуальных функций, на самом деле он создан для использования в качестве базового класса и не противоречит рассматриваемой рекомендации. (Однако класс
unary_function
может быть усовершенствован добавлением защищенного деструктора — см. рекомендацию 50.)

Ссылки

[Dewhurst03] §70, §93 • [Meyers97] §33 • [Stroustrup00] §24.2-3, §25.2

36. Предпочитайте предоставление абстрактных интерфейсов

Резюме

Вы любите абстракционизм? Абстрактные интерфейсы помогают вам сосредоточиться на проблемах правильного абстрагирования, не вдаваясь в детали реализации или управления состояниями. Предпочтительно проектировать иерархии, реализующие абстрактные интерфейсы, которые моделируют абстрактные концепции.

Обсуждение

Предпочитайте определять абстрактные интерфейсы и выполнять наследование от них. Абстрактный интерфейс представляет собой абстрактный класс, составленный полностью из (чисто) виртуальных функций и не обладающий состояниями (членами-данными), причем обычно без реализации функций-членов. Заметим, что отсутствие состояний в абстрактном интерфейсе упрощает дизайн всей иерархии (см. соответствующие примеры в [Meyers96]).

Желательно следовать принципу инверсии зависимостей (Dependency Inversion Principle, DIP; см. [Martin96a] и [Martin00]). Данный принцип состоит в следующем.

• Высокоуровневые модули не должны зависеть от низкоуровневых. И те, и другие должны зависеть от абстракций.

• Абстракции не должны зависеть от деталей; вместо этого детали должны зависеть от абстракций.

Из DIP следует, что корнями иерархий должны быть абстрактные классы, в то время как конкретные классы в этой роли выступать не должны (см. рекомендацию 35). Абстрактные базовые классы должны беспокоиться об определении функциональности, но не о ее реализации.

Принцип инверсии зависимостей имеет три фундаментальных преимущества при проектировании.

• Повышение надежности. Менее стабильные части системы (реализации) зависят от более стабильных частей (абстракций). Надежный дизайн — тот, в котором воздействие изменений ограничено. При плохом проектировании небольшие изменения в одном месте расходятся кругами по всему проекту и оказывают влияние на самые неожиданные части системы. Именно это происходит, когда проект строится на конкретных базовых классах.

• Повышение гибкости. Дизайн, основанный на абстрактных интерфейсах, в общем случае более гибок. Если абстракции корректно смоделированы, то при появлении новых требований легко разработать новые реализации. И напротив, дизайн, зависящий от многих конкретных деталей, оказывается более жестким в том смысле, что новые требования приводят к существенным изменениям в ядре системы.

• Хорошая модульность. Дизайн, опирающийся на абстракции, обладает хорошей модульностью благодаря простоте зависимостей: высокоизменяемые части зависят от стабильных частей, но не наоборот. Дизайн же, в котором интерфейсы перемешаны с деталями реализации, применить в качестве отдельного модуля в другой системе оказывается очень сложно.

Закон Второго Шанса гласит: "Самая важная вещь — интерфейс. Все остальное можно подправить и позже, но если интерфейс разработан неверно, то может оказаться так, что у вас уже не будет второго шанса его исправить" [Sutter04].

Поделиться:
Популярные книги

Вкус ледяного поцелуя

Полякова Татьяна Викторовна
2. Ольга Рязанцева
Детективы:
криминальные детективы
9.08
рейтинг книги
Вкус ледяного поцелуя

Проблема майора Багирова

Майер Кристина
1. Спецназ
Любовные романы:
современные любовные романы
6.60
рейтинг книги
Проблема майора Багирова

Прометей: владыка моря

Рави Ивар
5. Прометей
Фантастика:
фэнтези
5.97
рейтинг книги
Прометей: владыка моря

Попаданка в академии драконов 4

Свадьбина Любовь
4. Попаданка в академии драконов
Любовные романы:
любовно-фантастические романы
7.47
рейтинг книги
Попаданка в академии драконов 4

(Не)зачёт, Дарья Сергеевна!

Рам Янка
8. Самбисты
Любовные романы:
современные любовные романы
5.00
рейтинг книги
(Не)зачёт, Дарья Сергеевна!

Запасная дочь

Зика Натаэль
Фантастика:
фэнтези
6.40
рейтинг книги
Запасная дочь

Дракон с подарком

Суббота Светлана
3. Королевская академия Драко
Любовные романы:
любовно-фантастические романы
6.62
рейтинг книги
Дракон с подарком

Отвергнутая невеста генерала драконов

Лунёва Мария
5. Генералы драконов
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Отвергнутая невеста генерала драконов

Случайная жена для лорда Дракона

Волконская Оксана
Фантастика:
юмористическая фантастика
попаданцы
5.00
рейтинг книги
Случайная жена для лорда Дракона

Тройняшки не по плану. Идеальный генофонд

Лесневская Вероника
Роковые подмены
Любовные романы:
современные любовные романы
6.80
рейтинг книги
Тройняшки не по плану. Идеальный генофонд

Идеальный мир для Лекаря 28

Сапфир Олег
28. Лекарь
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Идеальный мир для Лекаря 28

Лейтенант космического флота

Борчанинов Геннадий
1. Звезды на погонах
Фантастика:
боевая фантастика
космическая фантастика
космоопера
рпг
фэнтези
фантастика: прочее
5.00
рейтинг книги
Лейтенант космического флота

Гарем на шагоходе. Том 5

Гремлинов Гриша
5. Волк и его волчицы
Фантастика:
боевая фантастика
фэнтези
5.00
рейтинг книги
Гарем на шагоходе. Том 5

Матабар III

Клеванский Кирилл Сергеевич
3. Матабар
Фантастика:
фэнтези
5.00
рейтинг книги
Матабар III