Информационный сайт

 

Реклама
bulletinsite.net -> Книги на сайте -> Программисту -> Мизрохи С.В. -> "Turbo Pascal и объектно-ориентированное программирование" -> 70

Turbo Pascal и объектно-ориентированное программирование - Мизрохи С.В.

Мизрохи С.В. Turbo Pascal и объектно-ориентированное программирование — М.: Финансы и статистика , 1992. — 192 c.
ISBN 5-279-00903-2
Скачать (прямая ссылка): efektispolzc2000.djvu
Предыдущая << 1 .. 64 65 66 67 68 69 < 70 > 71 72 73 74 75 76 .. 105 >> Следующая

Наследование и ООП
соглашаются с тем, что интерфейс и реализация по умолчанию должны быть разделены. Как разрешить кажущееся противоречие? Для этого используют тот факт, что производные классы должны переопределять чисто виртуальные функции, которые могут иметь и свою собственную реализацию. Вот как допускается использовать возможность определения чисто виртуальных функций в иерархии Airplane:
class Airplane { public:
virtual void fly (const Airports destination) = 0;
};
void Airplane: : fly (const Airports destination) {
код по умолчанию для полета самолета
б заданный пункт назначения - destination
}
class ModelA: public Airplane { public :
virtual void fly(const Airports destination) { Airplane.-: fly (destination) ; }
};
class ModelB: public Airplane { public :
virtual void fly(const Airports destination) { Airplane:: fly(destination); }
};
class ModelC: public Airplane { public:
virtual void fly(const Airports destination);
};
void ModelC: : fly (const Airports destination) {
код для полета самолета типа ModelC в заданный пункт назначения }
Это практически такой же подход, как и прежде, за исключением того, что тело чисто виртуальной функции Airplane: : fly играет роль отдельной функций Airplane: : defaul tFly. По существу, fly была разбита на две основные составляющие. Объявление задает интерфейс (который должен быть использован в производном классе), а определение задает действия по умолчанию (которые могут быть использованы производным классом, но только по явному требованию)-Однако, производя слияние fly и defaultFly, мы теряем возможность задать для функций различные уровни доступа: код, который был защищенным (функция def aultFly), стал открытым (поскольку теперь он находится в fly)-
И наконец, пришла очередь невиртуальной функции класса Shape - obj ectlD-Когда функция-член объявлена невиртуальной, не предполагается, что она буде? вести себя иначе в производных классах. В действительности невиртуальные
Правило 36
157
функции-члены выражают инвариант относительно специализации, поскольку они определяют поведение, которое должно сохраняться вне зависимости от того, как специализируются производные классы. Справедливо следующее: цель объявления невиртуальной функции - заставить производные классы наследовать интерфейс функции, а также ее обязательную реализацию.
Вы можете представлять себе объявление Shape: :objectID как утверждение: «Каждый объект Shape имеет функцию, которая дает идентификатор объекта, и идентификатор объекта всегда вычисляется одним и тем же образом. Это поведение задается определением функции Shape: : object ID, и никакой производный класс не должен изменять поведение». Поскольку невиртуальная функция определяет инвариант относительно специализации, ее не следует перетру-жать в производных классах (этот вопрос подробно обсуждается в правиле 37).
Различия в объявлениях чисто виртуальных, просто виртуальных и невиртуальных функций позволяют точно указать, что, по вашему замыслу, должны наследовать производные классы: только интерфейс, интерфейс и реализацию по умолчанию или интерфейс и обязательную реализацию соответственно. Поскольку эти типы объявлений означают принципиально разные вещи, следует осуществлять продуманный выбор между этими вариантами, когда вы объявляете функции-члены класса. При этом вы должны избегать двух ошибок, чаще всего совершаемых неопытными разработчиками классов.
Первая ошибка - объявление всех функций невиртуальными. Это не оставляет возможности для маневров в производных классах; при этом больше всего проблем вызывают невиртуальные деструкторы (см. правило 14). Конечно, нет ничего плохого в проектировании классов, которые не следует использовать в качестве базовых. В этом случае вполне уместен набор из одних только невиртуальных функций-членов. Однако очень часто такие классы объявляются либо из-за незнания различий между виртуальными и невиртуальными функциями, либо в результате необоснованного беспокойства по поводу потери* производительности при использовании виртуальных функций. Факт остается фактом: практически любой класс, который должен использоваться как базовый, будет содержать виртуальные функции (снова см. правило 14).
Если вы обеспокоены тем, во что вам обходится использование виртуальных Функций, разрешите мне напомнить о так называемом «правиле 80-20» (см. также правило 33), которое утверждает, что в типичной программе 80% времени исполнения затрачивается на 20% кода. Это правило крайне важно, поскольку оно означает, что в среднем 80% ваших функций могут быть виртуальными, не оказывая никакого ощутимого влияния на общую производительность вашей программы. Поэтому, прежде чем начать беспокоиться о том, можете ли вы позволять себе использование виртуальных функций, сначала убедитесь, что вы имеете дело с теми Двадцатью процентами программы, для которых ваши решения окажут существенное влияние на производительность.
Другая распространенная ошибка - объявлять все функции-члены виртуальными. Иногда это вполне правильный подход, о чем свидетельствуют, например, 1слассы-протоколы (см. правило 34). Однако данное решение может также навести На мысль, что у разработчика нет ясного понимания задачи. Некоторые функции Не должны переопределяться в производных классах, и в таком случае вы должны
Предыдущая << 1 .. 64 65 66 67 68 69 < 70 > 71 72 73 74 75 76 .. 105 >> Следующая
Реклама
Авторские права © 2009 AdsNet. Все права защищены.
Rambler's Top100