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

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

Определение в производном классе перекрытия, которое может быть неуспешным (например, генерировать исключения; см. рекомендацию 70), будет корректно только в том случае, когда в базовом классе не объявлено, что данная операция всегда успешна. Например, скажем, класс Employee содержит виртуальную функцию-член GetBuilding, предназначение которой — вернуть код здания, в котором работает объект Employee. Но что если мы захотим написать производный класс RemoteContractor, который перекрывает функцию GetBuilding, в результате чего она может генерировать исключения или возвращать нулевой код здания? Такое поведение корректно только в том случае, если в документации класса Employee указано, что функция GetBuilding может завершаться неуспешно, и в классе RemoteContractor сообщение о неудаче выполняется документированным в классе Employee способом.

Никогда не изменяйте аргумент по умолчанию при перекрытии. Он не является частью сигнатуры функции, и клиентский код будет невольно передавать различные аргументы в функцию, в зависимости от того, какой узел иерархии обращается к ней. Рассмотрим следующий пример:

class Base {

 // ...

 virtual void Foo(int x = 0);

};

class Derived : public Base {

 // ...

 virtual void Foo(int x = 1); // лучше так не делать...

};

Derived *pD = new Derived;

pD->Foo(); // Вызов pD->Foo(1)

Base *pB = pD;

pB->Foo(); // вызов pB->Foo(0)

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

Желательно добавлять ключевое слово virtual при перекрытии функций, несмотря на его избыточность — это сделает код более удобным для чтения и понимания.

Не забывайте о том, что перекрытие может скрывать перегруженные функции из базового класса, например:

class Base{                   // ...

 virtual void Foo(int);

 virtual void Foo(int, int);

 void Foo(int, int, int);

};

class Derived : public Base { // ...

 virtual void Foo(int);       // Перекрывает Base::Foo(int),

                              // скрывая остальные функции

};

Derived d;

d.Foo(1);                     // Все в порядке

d.Foo(1, 2);                  // Ошибка

d.Foo(1, 2, 3);               // Ошибка

Если перегруженные функции из базового класса должны быть видимы, воспользуйтесь объявлением using для того, чтобы повторно объявить их в производном классе:

class Derived : public Base { // ...

 virtual void Foo(int);       // Перекрытие Base::Foo(int)

 using Base::Foo;             // вносит все прочие перегрузки

                              // Base::Foo в область видимости

};

Примеры

Пример: Ostrich (Страус). Если класс Bird (Птица) определяет виртуальную функцию Fly и вы порождаете новый класс Ostrich (известный как птица, которая не летает) из класса Bird, то как вы реализуете Ostrich::Fly? Ответ стандартный — "по обстоятельствам". Если Bird::Fly гарантирует успешность (т.е. обеспечивает гарантию бессбойности; см. рекомендацию 71), поскольку способность летать есть неотъемлемой частью модели Bird, то класс Ostrich оказывается неадекватной реализацией такой модели.

Ссылки

[Dewhurst03] §73-74, §78-79 • [Sutter00] §21 • [Keffer95] p. 18

<p>39. Виртуальные функции стоит делать неоткрытыми, а открытые — невиртуальными</p>Резюме
Перейти на страницу:

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

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

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

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

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

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

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

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

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

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

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

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

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