Б. Страуструп - Дизайн и Эволюция C++. 2006 (1160775), страница 69
Текст из файла (страница 69)
Может, стоило реанимировать понятие о функциях са11 и гесцхп (см. раздел 2.11 3) в подражание методам: Ье йоге и: а йсех, имеющимся в языке СЕ 0$, но пользователи и так жалуются на сложности механизмов множественного наследования. :!ИИ>ИИИН Комбинирование методов Вместе с тем методы легко комбинировать вручную. Главное — избежать нескольких вызовов функции из виртуального класса, если это нежелательно. Вот один из возможных подходов: с1авв И ( ртосессед: уо[д 1() ( /" выполняет то, что необходимо самому И */ ) // рпЫ1с: чо1д 1() ( 1(); ) // )! с1авв А: рыЫ1с у[тлпа1 И ( рголеслед: уо1д 1() ( /* выполняет то, что необходимо А */ // рпЫ1с." чотд 1() ( 1(); н:: 1(); ) // ); с1авв В : рпЫ1с у1тепа1 и ( // ртосессед: чо[д 1() [ /* выполняет то, что необходимо В */ ) // рпЫ1с: чо(д 1() ( 1(); И:: 1(); ) // ); В частности, такой стиль позволяет в классе, который косвенно произведен от класса и дважды, вызывать Х:: 1 () только один раз: с1авв С: рпЫ1с А, рсЫ1с В, рсЫ[с у[тспа1 Х ( // ртосессед: уо1д 1() ( /* выполняет то, что необходимо С *! ) // рпЫ)с: уо1д 1() ( 1(); А;: 1(); В:: 1(); Х:: 1(); ) // В каждом классе имеется защищенная функция 1 ( ), выполняющая операции, необходимые самому классу, и используемая производными классами.
Есть также открытая функция б [ ), которая является интерфейсом, предлагаемым сторонним классам, функциям и тд. В производном классе б () вызывает собственную б () и позволяет базовым классам вызвать их т (); Множественное наследование ИИИИИИИВ Это менее удобно, чем автоматически генерируемые составные функции, но в некоторых отношениях обладает большей гибкостью. 12.б.
Полемика о множественном наследовании Множественное наследование в С++ вызвало споры ([Сагйй!, 199 Ц, [Саггой, 199Ц, [ЪаЫо, 199Ц, [8а1Й1пеп, 1992[, [Ъга!до, 19931) по нескольким причинам. Аргументы против него в основном касались реальной и воображаемой сложности концепции, ее полезности и влияния, которое она оказывает на другие средства языка и инструментальные средства: о множественное наследование виделось как первое существенное расширение С++. Некоторые опытные пользователи С++ считали, что это ненужное усложнение, которое повлечет за собой поток новых средств. Например, на самой первой конференции по С++ в Санта-Фе (см. раздел 7.1.2) Том Каргилл сорвал аплодисменты, высказав забавное, но не очень реалистичное предложение: каждый, кто предлагает включить в С++ новое средство, должен сказать, какое из старых средств, равных по сложности новому, следует исключить.
Мне такой подход нравится, но я все же не могу утверждать, что С++ стал бы лучше, не будь в нем множественного наследования, или что С++ образца 1985 г. лучше, чем С++ 1993 г. Веселье продолжил Джим Уолдо ([пп ЪЧаЫо). Он продолжил мысль Тома, высказав следующую идею: обязать предлагающих новые средства пожертвовать... свою почку. Это, по мнению Джима, заставит каждого не один раз подумать, прежде чем вносить предложение, причем даже лишенные инстинкта самосохранения не смогут внести более двух предложений. Впрочем, не все были так настроены против новых возможностей, как можно было бы подумать, читая журналы, сетевые новости и выслушивая вопросы, задаваемые после доклада; о я реализовал множественное наследование так, что издержки неизбежны даже для тех, кто пользуется лишь одиночным. Это нарушает правило «чем не пользуетесь, за то не платите» (см.
раздел 4.5) и создает ложное впечатление, что множественное наследование якобы неэффективно вовсе. Такие издержки казались мне вполне приемлемыми, потому что они совсем невелики (один доступ к массиву плюс одно сложение на каждый вызов виртуальной функции) и потому что я знал простой способ реализации множественного наследования без всяких изменений реализации вызовов виртуальных функций в иерархии одиночного наследования (см.
раздел 12А). Я выбрал такую «субоптимальную» реализацию, поскольку она в наибольшей степени переносима; о 8ша1йа[к не поддерживает множественное наследование, а для многих пользователей слова «объектно-ориентированное программирование» и «5тайгав㻠— синонимы. Такие люди часто подозревают, что если 5шайга)к не поддерживает какую-то возможность, то она либо плоха, либо не нужна. Разумеется, я не разделяю этих взглядов. Очевидно, 5шайгайг и выиграл бы от наличия множественного наследования, возможно, — нет; это не имеет отношения к делу. Однако мне было ясно, что некоторые приемы, которые Полемика о множественном наследовании ЩфффЯЩИ ревнители БшаПга! к предлагали в качестве альтернатив множественному наследованию, не годились для статически типизированного языка, каким является С++. Языковые войны почти всегда бессмысленны; те же из них, которые развертываются вокруг отдельного средства языка без учета всего окружения, бессмысленны вдвойне.
Нападки на множественное наследование, которые на самом деле направлены на статическую систему типов или являются простым отражением воображаемых атак на Бша1!са1к, лучше просто не принимать во внимание; ш мое изложение множественного наследования [Бтгоцзггир, 19871 было перенасыщено техническими деталями, акцентировало внимание на вопросах реализации и плохо объясняло то, как им можно воспользоваться в программировании, В результате многие решили, что у множественного наследованяя мало применений, а реализовать его безмерно трудно.
Подозреваю, что, если бы я в той же манере изложил принципы одиночного наследования, вывод был бы аналогичным; о некоторыс пользователи убеждены, что множественное наследование неудачно в принципе, поскольку «его слишком трудно использовать, а значит, результатом будет плохое проектирование и изобилующие ошибками программы». Конечно, множественное наследование можно употребить во вред, как, впрочем, и любое другое неординарное средство языка.
Но мне известны реальные программы, которые с помощью множественного наследования удалось структурировать лучше, чем при использовании одиночного. При этом не просматривались очевидные альтернативы, которые позволили бы упростить структуру или сопровожление программы.
Видимо, некоторыс обвинения в адрес множественного наследования (дескать, оно является источником ошибок) основаны исключительно на опыте работы с другими языками, которые не могут диагностировать ошибки на стадии компиляции так же хорошо, как С++; д ряд пользователей считает множественное наследование слишком слабым механизмом и в качестве альтернативы указывает на делегирование. Делегирование — это механизм, позволяющий перепоручить операцию другому объекту во время выполнения [Бггоцзтгцр, 19871. Один из вариантов делегирования был реализован и испытан в С++.
Результаты обескуражили: практически все пользователи столкнулись с серьезными трудностями вследствие разных изъянов в разработке своей программы, основанной на делегировании (см, раздел 12.7); о утверждалось, что само по себе множественное наследование приемлемо, но его включение в С++ приводит к трудностям с другими потенциальными возможностями языка, например со сборкой мусора, и без необходимости усложняет построение инструментальных средств, в частности, баз данных для С++.
Безусловно, множественное наслелование усложняет создание инструментария. Но только время покажет, перевешивает ли усложнение преимущества при проектировании и реализации приложений, которые дает такое наследование; ИИИИИИИ6 Множественное наследование о после включения множественного наследования в С++ говорилось, что идея хороша, но ее воплощение неудачно. Такие аргументы могут представлять интерес для проектировщиков «С+++»», но мне они не очень помогают в работе над языком, его инструментальными средствами и приемами программирования на нем. Пользователи нечасто приводят практические свидетельства в пользу желаемых улучшений, сами предложения редко доводятся до деталей, варианты радикально отличаются друг от друга, а проблемы, связанные с изменением существующих правил, почти никогда не рассматриваются.