Материалы книги получены с http://www.itlibitum.ru/
Нормальное наследование
Класс Grandpa может содержать не чисто виртуальные функции и переменные и при всем этом обеспечивать полную взаимозаменяемость. Тем не менее, совпадение интерфейсов еще не означает взаимозаменяемости объектов. Приходится учитывать действие вторичных эффектов. Предположим, функция Fn1() класса Grandpa не является чисто виртуальной:
void Grandpa::Fn1()
{
// Код, вызывающий вторичные эффекты
}
void Dad::Fn1()
{
// Код, вызывающий другие вторичные эффекты
}
void AuntMartha::Fn1()
{
Grandpa::Fn1();
// Прочее
}
Клиент Grandpa может полагаться на вторичные эффекты этого класса. Знаю, знаю, инкапсуляция и все такое, на вторичные эффекты полагаться никогда не следует… но давайте спустимся на землю.
Функции, которые мы вызываем, выполняют различные действия - скажем, рисуют на экране, создают объекты или записывают информацию в файле. Без этих вторичных эффектов толку от них будет немного. Если Grandpa обладает некоторыми встроенными вторичными эффектами, клиенты Grandpa могут с полным правом надеяться, что эти эффекты сохранятся во всех производных классах.
Но вот Dad усомнился в авторитете Grandpa и в своем переопределении Fn1() не потрудился вызвать Grandpa::Fn1(). Вторичные эффекты Grandpa::Fn1() пропадают. Рано или поздно это начнет беспокоить клиента Grandpa, которые, возможно, ждал от Dad совсем иного. А вот AuntMartha в свом переопеределении вызывает Grandpa::Fn1() и потому сохраняет все вторичные эффекты Grandpa::Fn1(). Теперь AuntMartha может выполнять любые дополнительные действия в пределах разумного - клиентов Grandpa это совершенно не интересует.
Если переопределенная функция вызывает версию базового класса, говорят, что она нормально наследуется от этой функции. Не важно, где находится этот вызов - в начале, в конце или середине переопределенной функции. Важно лишь то, что в какой-то момент он все же происходит. Если все переопределенные функции производного класса наследуются нормально, говорят, что весь класс наследуется нормально. Если все производные классы гомоморфного базового класса наследуются нормально и ни один из них не обладает особо вопиющими вторичными эффектами, их можно подставлять вместо друг друга.
Самый простой способ обеспечить взаимозаменяемость - сделать все функции Grandpa чисто виртуальными. Это вырожденный случай нормального наследования; если функция базового класса является чисто виртуальной, то все ее вторичные эффекты (которых на самом деле нет) сохраняются по определению.
Назад Содержание Далее
|