Читаем Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ полностью

Когда вы поймете истинное назначение различных средств C++, то обнаружите, что ваш взгляд на ООП изменился. Вместо простого упражнения в нахождении отличий между языками это станет средством выражения того, что вы хотите сказать о своей программной системе. А поняв, что же вы в действительности имеете в виду, уже не составит большого труда перевести свои мысли этого на C++.

<p>Правило 32: Используйте открытое наследование для моделирования отношения «является»</p>

Вильям Демент (William Dement) в своей книге «Кто-то должен бодрствовать, пока остальные спят» (W. H. Freeman and Company, 1974) рассказывает о том, как он пытался донести до студентов наиболее важные идеи своего курса. Утверждается, говорил он своей группе, что средний британский школьник помнит из уроков истории лишь то, что битва при Хастингсе произошла в 1066 году. Даже если ученик почти ничего не запомнил из курса истории, подчеркивает Демент, 1066 год остается в его памяти. Демент пытался внушить слушателям несколько основных идей, в частности ту любопытную истину, что снотворное вызывает бессонницу. Он призывал своих студентов запомнить ряд ключевых фактов, даже если забудется все, что обсуждалось на протяжении курса, и в течение семестра возвращался к нескольким фундаментальным заповедям.

Последним на заключительном экзамене был вопрос: «Напишите, какой факт из тех, что обсуждались на лекциях, вы запомните на всю жизнь». Проверяя работы, Демент был ошеломлен. Почти все упомянули 1066 год.

Теперь я с трепетом хочу провозгласить, что самое важное правило в объектно-ориентированном программировании на C++ звучит так: открытое наследование означает «является». Твердо запомните это.

Если вы пишете класс D (derived – «производный») открыто наследует классу B («base» – «базовый»), то тем самым сообщаете компилятору C++ (а заодно и людям, читающим ваш код), что каждый объект типа D является также объектом типа B, но не наоборот. Вы говорите, что B представляет собой более общую концепцию, чем D, а D – более конкретную концепцию, чем B. Вы утверждаете, что везде, где может быть использован объект B, можно использовать также объект D, потому что D является объектом типа B. С другой стороны, если вам нужен объект типа D, то объект B не подойдет, поскольку каждый D «является разновидностью» B, но не наоборот.

Такой интерпретации открытого наследования придерживается C++. Рассмотрим следующий пример:

class Person {...};

class Student: public Person {...};

Здравый смысл и опыт подсказывают нам, что каждый студент – человек, но не каждый человек – студент. Именно такую связь подразумевает данная иерархия. Мы ожидаем, что всякое утверждение, справедливое для человека – например, что у него есть дата рождения, – справедливо и для студента, но не все, что верно для студента – например, что он учится в каком-то определенном институте, – верно для человека в общем случае.

Применительно к C++ это выглядит следующим образом: любая функция, которая принимает аргумент типа Person (или указатель на Person, или ссылку на Person), примет объект типа Student (или указатель на Student, или ссылку на Student):

void eat(const Person& p); // все люди могут есть

void study(const Student& s); // только студент учится

Person p; // p – человек

Student s; // s – студент

eat(p); // правильно, p есть человек

eat(s); // правильно, s – это студент,

// и студент также является человеком

study(s); // правильно

study(p); // ошибка! p – не студент

Все сказанное верно только для открытого наследования. C++ будет вести себя так, как описано выше, только в случае, если Student открыто наследует Person. Закрытое наследование означает нечто совсем иное (см. правило 39), а смысл защищенного наследования ускользает от меня по сей день.

Идея тождества открытого наследования и понятия «является» кажется достаточно очевидной, но иногда интуиция нас подводит. Рассмотрим следующий пример: пингвин – это птица, птицы умеют летать. Если вы по наивности попытаетесь выразить это на C++, то вот что получится:

class Bird {

public:

virtual void fly(); // птицы умеют летать

...

};

class Penguin: public Bird { // пингвины – птицы

...

};

Неожиданно мы столкнулись с затруднением. Утверждается, что пингвины могут летать, что, как известно, неверно. В чем тут дело?

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

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

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

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

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

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

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

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

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