Программирование >>  Полиморфизм без виртуальных функций в с++ 

1 ... 85 86 87 [ 88 ] 89 90 91 ... 144


ревнители Smalltalk предлагали в качестве альтернатив множественному наследованию, не годились для статически типизированного языка, каким является C-I-+. Языковые войны почти всегда бессмысленны; те же из них, которые развертываются вокруг отдельного средства языка без учета всего окружения, бессмысленны вдвойне. Нападки на множественное наследование, которые на самом деле направлены на статическую систему типов или являются простым отражением воображаемых атак на Smalltalk, лучше просто не принимать во внимание;

□ .мое изложение .множественного наследования [Stroustrup, 1987] было перенасыщено техническими деталями, акцентировало внимание на вопросах реализации и плохо объясняло то, как им можно воспользоваться в программировании. В результате многие решили, что у множественного наследования мало применений, а реализовать его безмерно трудно. Подозреваю, что, если бы я в той же манере изложил принципы одиночного наследования, вывод был бы аналогичным;

□ некоторые полызователи убеждены, что множественное наследование неудачно в принципе, поскольку его слишком трудно использовать, а значит, результатом будет плохое проектирование и изобилующие ошибками программы . Конечно, множественное наследование можно употребить во вред, как, впрочем, и любое другое неординарное средство языка. Но мне известны реальные программы, которые с помощью множественного наследования удалось структурировать лучше, чем при использовании одиночного. При это.м не просматривались очевидные альтернативы, которые позволили бы упростить структуру или сопровождение программы. Видимо, некоторые обвинения в адрес множественного наследования (дескать, оно является источпико.м ошибок) основаны исключительно на опыте работы с другими языками, которые не могут диагностировать ошибки на стадии компиляции так же хорошо, как C-I-+;

□ ряд пользователей считает множественное наследование слишком слабым механизмом и в качестве альтернативы указывает на делегирование. Делегирование - это механизм, позволяющий перепоручить операцию другому объекту во время выполнения [Stroustrup, 1987]. Один из вариантов делегирования был реализован и испытан в С++. Результаты обескуражили: практически все пользователи столкнулись с серьезными трудностями вследствие разных изъянов в разработке своей программы, основанной на делегировании (см. раздел 12.7);

□ утверждалось, что само по себе множественное наследование приемлемо, но его включение в С++ приводит к трудностям с другими потенциальными возможностями языка, например со сборкой мусора, и без необходимости усложняет построение инструментальных средств, в частности, баз данных для С++. Безусловно, множественное наследование усложняет создание ин-стру.ментария. Но только время покажет, перевешивает ли усложнение преимущества при проектировании и реализации приложений, которые дает такое наследование;



□ после включения множественного наследования в С++ говорилось, что идея хороша, но ее воплошение неудачно. Такие аргументы могут представлять интерес для проектировщиков С++++ , но мне они не очень помогают в работе над языком, его инструментальными средствами и приемами программирования на нем. Пользователи нечасто приводят практические свидетельства в пользу желаемых улучшений, сами предложения редко доводятся до деталей, варианты радикально отличаются друг от друга, а проблемы, связанные с изменением существующих правил, почти никогда не рассматриваются.

Сейчас, как и тогда, я думаю, что у всех вышеупо.мянутых доводов есть один общий недостаток - множественное наследование в них трактуется чересчур серьезно. А ведь это средство не решает - да и не должно решать - всех проблем, поскольку обходится слишком дешево. Иметь в своем распоряжении множественное наследование иногда удобно. Грейди Буч [Booch, 1991] выразил эту мысль чуть более экспрессивно: Множественное наследование - как парашют; необязательно пользоваться им часто. Зато, когда возникает необходимость, без него не обойтись . Такое мнение частично основано на опыте, приобретенном при переписывании компонент Буча с Ada на С++ (см. раздел 8.4.1). Библиотека контейнерных классов и ассоциированных с ними операций, которую реализовали Грейди Буч и Майк Вило, - это один из лучших примеров применения множественного наследования [Booch, 1990], [Booch, 1993b].

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

По всей вероятности, наиболее удачно множественное наследование применяется в следующих ситуациях:

□ объединение независимых или почти независимых иерархий; примером могут служить классы task и displayed (см. раздел 12.2);

□ композиция интерфейсов; примером является библиотека потокового ввода/вывода (см. раздел 12.3);

□ составление класса из интерфейса и реализации; пример - класс slist set (см. раздел 13.2.2).

Дальнейшие примеры множественного наследования можно найти в разделах 13.2.2, 14.2.7 и 16.4.

В основном неудачи связаны с попытками насильно внедрить стиль, чуждый С++. В частности, прямое копирование применяемого в CLOS стиля проектирования, который основан на линеаризации разрешения неоднозначности, сопоставлении имен, разделяемых в иерархии, и применении методов : before и : after для создания составных операций, значительно усложняет большие программы.




int Ь

Рис. 12.10

Концепция выглядела многообещающей для представления структур, требующих большей гибкости, чем .может дать обычное наследование. В частности, присваивание делегирующему указателю могло бы использоваться для изменения конфигурации объекта во вре.мя выполнения. Реализация была тривиальной, затраты - минимальными. Поэтому данную идею испытали несколько пользователей. Много времени и сил здесь положил Билл Хопкинс (Bill Hopkins). К сожалению, все пользователи, при.менившие механизм делегирования, пострадали от серьезных ошибок и путаницы. Из-за этого возможность была исключена как из проекта, так и из Cfront версии 2.0.

Причины ошибок:

□ функции в делегирующем классе не замещают функции в классе, которому операция делегируется;

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

Ясно, что две эти проблемы взаимосвязаны. Разумеется, пользователи были предупреждены. Предостережения не помогли. Более того, я са.м забыл собственные

12.7. Делегирование

в первоначальном проекте множественного наследования, который был представлен на Европейской конференции группы пользователей UNIX, состоявшейся в Хельсинки в мае 1987 г. [Stroustrup, 1987J, фигурировало понятие делегирования [Agha, 1986].

Пользователю разрешалось задать указатель на некоторый класс вместе с именами базовых классов в объявлении класса. Описанный таким образом объект использовался точно так же, как если бы это был объект, представляющий базовый класс. Например:

class В { int b; void f(); }; class С : *p { В* p; int C; };

Нотация : *p означает, что объект, на который указывает р, будет использоваться так, будто он представляет базовый класс для С.

void f(C* q) {

q->f(); означает q->p->f()

После инициализации С: :р объект класса С выглядел бы примерно так, как это показано иа рис. 12.10.



1 ... 85 86 87 [ 88 ] 89 90 91 ... 144

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика